ir-rc5-decoder.c revision 724e2495502a98aaa3f93c404472a991da8ff857
1db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab/* ir-rc5-decoder.c - handle RC-5 IR Pulse/Space protocol
2db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab *
3db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
4db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab *
5db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab * This program is free software; you can redistribute it and/or modify
6db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab *  it under the terms of the GNU General Public License as published by
7db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab *  the Free Software Foundation version 2 of the License.
8db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab *
9db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab *  This program is distributed in the hope that it will be useful,
10db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab *  GNU General Public License for more details.
13db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab */
14db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
15db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab/*
16db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab * This code only handles 14 bits RC-5 protocols. There are other variants
17db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab * that use a different number of bits. This is currently unsupported
189b09df51b8c2b4615376e5ada3e2eb7eeed3cf5dMauro Carvalho Chehab * It considers a carrier of 36 kHz, with a total of 14 bits, where
199b09df51b8c2b4615376e5ada3e2eb7eeed3cf5dMauro Carvalho Chehab * the first two bits are start bits, and a third one is a filing bit
20db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab */
21db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
22db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab#include <media/ir-core.h>
23db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
249b09df51b8c2b4615376e5ada3e2eb7eeed3cf5dMauro Carvalho Chehab#define RC5_NBITS		14
25724e2495502a98aaa3f93c404472a991da8ff857David Härdeman#define RC5_UNIT		888888 /* ns */
26db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
27db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab/* Used to register rc5_decoder clients */
28db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehabstatic LIST_HEAD(decoder_list);
296eb9435b874ae5ff56d56952167a8e9be5c5deebMauro Carvalho Chehabstatic DEFINE_SPINLOCK(decoder_lock);
30db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
31db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehabenum rc5_state {
32db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	STATE_INACTIVE,
33724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	STATE_BIT_START,
34724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	STATE_BIT_END,
35724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	STATE_FINISHED,
36db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab};
37db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
38db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehabstruct decoder_data {
39db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	struct list_head	list;
40db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	struct ir_input_dev	*ir_dev;
41db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	int			enabled:1;
42db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
43db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	/* State machine control */
44db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	enum rc5_state		state;
45724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	u32			rc5_bits;
46724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	int			last_unit;
47724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	unsigned		count;
48db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab};
49db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
50db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
51db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab/**
52db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab * get_decoder_data()	- gets decoder data
53db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab * @input_dev:	input device
54db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab *
55db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab * Returns the struct decoder_data that corresponds to a device
56db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab */
57db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
58db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehabstatic struct decoder_data *get_decoder_data(struct  ir_input_dev *ir_dev)
59db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab{
60db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	struct decoder_data *data = NULL;
61db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
62db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	spin_lock(&decoder_lock);
63db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	list_for_each_entry(data, &decoder_list, list) {
64db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab		if (data->ir_dev == ir_dev)
65db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab			break;
66db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	}
67db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	spin_unlock(&decoder_lock);
68db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	return data;
69db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab}
70db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
71db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehabstatic ssize_t store_enabled(struct device *d,
72db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab			     struct device_attribute *mattr,
73db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab			     const char *buf,
74db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab			     size_t len)
75db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab{
76db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	unsigned long value;
77db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	struct ir_input_dev *ir_dev = dev_get_drvdata(d);
78db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	struct decoder_data *data = get_decoder_data(ir_dev);
79db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
80db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	if (!data)
81db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab		return -EINVAL;
82db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
83db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	if (strict_strtoul(buf, 10, &value) || value > 1)
84db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab		return -EINVAL;
85db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
86db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	data->enabled = value;
87db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
88db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	return len;
89db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab}
90db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
91db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehabstatic ssize_t show_enabled(struct device *d,
92db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab			     struct device_attribute *mattr, char *buf)
93db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab{
94db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	struct ir_input_dev *ir_dev = dev_get_drvdata(d);
95db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	struct decoder_data *data = get_decoder_data(ir_dev);
96db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
97db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	if (!data)
98db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab		return -EINVAL;
99db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
100db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	if (data->enabled)
101db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab		return sprintf(buf, "1\n");
102db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	else
103db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	return sprintf(buf, "0\n");
104db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab}
105db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
106db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehabstatic DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
107db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
108db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehabstatic struct attribute *decoder_attributes[] = {
109db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	&dev_attr_enabled.attr,
110db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	NULL
111db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab};
112db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
113db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehabstatic struct attribute_group decoder_attribute_group = {
114db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	.name	= "rc5_decoder",
115db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	.attrs	= decoder_attributes,
116db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab};
117db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
118db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab/**
119724e2495502a98aaa3f93c404472a991da8ff857David Härdeman * ir_rc5_decode() - Decode one RC-5 pulse or space
120db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab * @input_dev:	the struct input_dev descriptor of the device
121724e2495502a98aaa3f93c404472a991da8ff857David Härdeman * @duration:	duration of pulse/space in ns
122db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab *
123db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab * This function returns -EINVAL if the pulse violates the state machine
124db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab */
125724e2495502a98aaa3f93c404472a991da8ff857David Härdemanstatic int ir_rc5_decode(struct input_dev *input_dev, s64 duration)
126db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab{
127db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	struct decoder_data *data;
128db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
129724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	u8 command, system, toggle;
130724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	u32 scancode;
131724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	int u;
132db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
133db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	data = get_decoder_data(ir_dev);
134db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	if (!data)
135db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab		return -EINVAL;
136db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
1377f20d32d446097789ade5ada6b645742ddac4eceMauro Carvalho Chehab	if (!data->enabled)
1387f20d32d446097789ade5ada6b645742ddac4eceMauro Carvalho Chehab		return 0;
1397f20d32d446097789ade5ada6b645742ddac4eceMauro Carvalho Chehab
140724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	if (IS_RESET(duration)) {
141db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab		data->state = STATE_INACTIVE;
142db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab		return 0;
143724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	}
144db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
145724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	u = TO_UNITS(duration, RC5_UNIT);
146724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	if (DURATION(u) == 0)
147724e2495502a98aaa3f93c404472a991da8ff857David Härdeman		goto out;
148db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
149724e2495502a98aaa3f93c404472a991da8ff857David Härdemanagain:
150724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	IR_dprintk(2, "RC5 decode started at state %i (%i units, %ius)\n",
151724e2495502a98aaa3f93c404472a991da8ff857David Härdeman		   data->state, u, TO_US(duration));
152db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
153724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	if (DURATION(u) == 0 && data->state != STATE_FINISHED)
154724e2495502a98aaa3f93c404472a991da8ff857David Härdeman		return 0;
155db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
156724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	switch (data->state) {
157db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
158724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	case STATE_INACTIVE:
159724e2495502a98aaa3f93c404472a991da8ff857David Härdeman		if (IS_PULSE(u)) {
160724e2495502a98aaa3f93c404472a991da8ff857David Härdeman			data->state = STATE_BIT_START;
161724e2495502a98aaa3f93c404472a991da8ff857David Härdeman			data->count = 1;
162724e2495502a98aaa3f93c404472a991da8ff857David Härdeman			DECREASE_DURATION(u, 1);
163724e2495502a98aaa3f93c404472a991da8ff857David Härdeman			goto again;
164724e2495502a98aaa3f93c404472a991da8ff857David Härdeman		}
165724e2495502a98aaa3f93c404472a991da8ff857David Härdeman		break;
166724e2495502a98aaa3f93c404472a991da8ff857David Härdeman
167724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	case STATE_BIT_START:
168724e2495502a98aaa3f93c404472a991da8ff857David Härdeman		if (DURATION(u) == 1) {
169724e2495502a98aaa3f93c404472a991da8ff857David Härdeman			data->rc5_bits <<= 1;
170724e2495502a98aaa3f93c404472a991da8ff857David Härdeman			if (IS_SPACE(u))
171724e2495502a98aaa3f93c404472a991da8ff857David Härdeman				data->rc5_bits |= 1;
172724e2495502a98aaa3f93c404472a991da8ff857David Härdeman			data->count++;
173724e2495502a98aaa3f93c404472a991da8ff857David Härdeman			data->last_unit = u;
174724e2495502a98aaa3f93c404472a991da8ff857David Härdeman
175724e2495502a98aaa3f93c404472a991da8ff857David Härdeman			/*
176724e2495502a98aaa3f93c404472a991da8ff857David Härdeman			 * If the last bit is zero, a space will merge
177724e2495502a98aaa3f93c404472a991da8ff857David Härdeman			 * with the silence after the command.
178724e2495502a98aaa3f93c404472a991da8ff857David Härdeman			 */
179724e2495502a98aaa3f93c404472a991da8ff857David Härdeman			if (IS_PULSE(u) && data->count == RC5_NBITS) {
180724e2495502a98aaa3f93c404472a991da8ff857David Härdeman				data->state = STATE_FINISHED;
181724e2495502a98aaa3f93c404472a991da8ff857David Härdeman				goto again;
182db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab			}
183db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
184724e2495502a98aaa3f93c404472a991da8ff857David Härdeman			data->state = STATE_BIT_END;
185724e2495502a98aaa3f93c404472a991da8ff857David Härdeman			return 0;
186724e2495502a98aaa3f93c404472a991da8ff857David Härdeman		}
187724e2495502a98aaa3f93c404472a991da8ff857David Härdeman		break;
1889b09df51b8c2b4615376e5ada3e2eb7eeed3cf5dMauro Carvalho Chehab
189724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	case STATE_BIT_END:
190724e2495502a98aaa3f93c404472a991da8ff857David Härdeman		if (IS_TRANSITION(u, data->last_unit)) {
191724e2495502a98aaa3f93c404472a991da8ff857David Härdeman			if (data->count == RC5_NBITS)
192724e2495502a98aaa3f93c404472a991da8ff857David Härdeman				data->state = STATE_FINISHED;
193724e2495502a98aaa3f93c404472a991da8ff857David Härdeman			else
194724e2495502a98aaa3f93c404472a991da8ff857David Härdeman				data->state = STATE_BIT_START;
195db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
196724e2495502a98aaa3f93c404472a991da8ff857David Härdeman			DECREASE_DURATION(u, 1);
197724e2495502a98aaa3f93c404472a991da8ff857David Härdeman			goto again;
198db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab		}
199724e2495502a98aaa3f93c404472a991da8ff857David Härdeman		break;
200724e2495502a98aaa3f93c404472a991da8ff857David Härdeman
201724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	case STATE_FINISHED:
202724e2495502a98aaa3f93c404472a991da8ff857David Härdeman		command  = (data->rc5_bits & 0x0003F) >> 0;
203724e2495502a98aaa3f93c404472a991da8ff857David Härdeman		system   = (data->rc5_bits & 0x007C0) >> 6;
204724e2495502a98aaa3f93c404472a991da8ff857David Härdeman		toggle   = (data->rc5_bits & 0x00800) ? 1 : 0;
205724e2495502a98aaa3f93c404472a991da8ff857David Härdeman		command += (data->rc5_bits & 0x01000) ? 0 : 0x40;
206724e2495502a98aaa3f93c404472a991da8ff857David Härdeman		scancode = system << 8 | command;
207724e2495502a98aaa3f93c404472a991da8ff857David Härdeman
208724e2495502a98aaa3f93c404472a991da8ff857David Härdeman		IR_dprintk(1, "RC5 scancode 0x%04x (toggle: %u)\n",
209724e2495502a98aaa3f93c404472a991da8ff857David Härdeman			   scancode, toggle);
210724e2495502a98aaa3f93c404472a991da8ff857David Härdeman		ir_keydown(input_dev, scancode, toggle);
211db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab		data->state = STATE_INACTIVE;
212db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab		return 0;
213db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	}
214db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
215724e2495502a98aaa3f93c404472a991da8ff857David Härdemanout:
216724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	IR_dprintk(1, "RC5 decode failed at state %i (%i units, %ius)\n",
217724e2495502a98aaa3f93c404472a991da8ff857David Härdeman		   data->state, u, TO_US(duration));
218db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	data->state = STATE_INACTIVE;
219db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	return -EINVAL;
220db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab}
221db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
222db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehabstatic int ir_rc5_register(struct input_dev *input_dev)
223db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab{
224db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
225db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	struct decoder_data *data;
226db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	int rc;
227db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
228db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
229db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	if (rc < 0)
230db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab		return rc;
231db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
232db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	data = kzalloc(sizeof(*data), GFP_KERNEL);
233db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	if (!data) {
234db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab		sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
235db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab		return -ENOMEM;
236db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	}
237db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
238db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	data->ir_dev = ir_dev;
239db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	data->enabled = 1;
240db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
241db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	spin_lock(&decoder_lock);
242db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	list_add_tail(&data->list, &decoder_list);
243db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	spin_unlock(&decoder_lock);
244db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
245db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	return 0;
246db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab}
247db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
248db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehabstatic int ir_rc5_unregister(struct input_dev *input_dev)
249db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab{
250db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
251db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	static struct decoder_data *data;
252db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
253db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	data = get_decoder_data(ir_dev);
254db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	if (!data)
255db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab		return 0;
256db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
257db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
258db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
259db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	spin_lock(&decoder_lock);
260db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	list_del(&data->list);
261db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	spin_unlock(&decoder_lock);
262db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
263db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	return 0;
264db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab}
265db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
266db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehabstatic struct ir_raw_handler rc5_handler = {
267db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	.decode		= ir_rc5_decode,
268db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	.raw_register	= ir_rc5_register,
269db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	.raw_unregister	= ir_rc5_unregister,
270db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab};
271db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
272db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehabstatic int __init ir_rc5_decode_init(void)
273db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab{
274db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	ir_raw_handler_register(&rc5_handler);
275db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
276db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	printk(KERN_INFO "IR RC-5 protocol handler initialized\n");
277db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	return 0;
278db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab}
279db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
280db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehabstatic void __exit ir_rc5_decode_exit(void)
281db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab{
282db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	ir_raw_handler_unregister(&rc5_handler);
283db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab}
284db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
285db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehabmodule_init(ir_rc5_decode_init);
286db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehabmodule_exit(ir_rc5_decode_exit);
287db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
288db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho ChehabMODULE_LICENSE("GPL");
289db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho ChehabMODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
290db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho ChehabMODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
291db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho ChehabMODULE_DESCRIPTION("RC-5 IR protocol decoder");
292