ir-rc5-decoder.c revision 667c9ebe97f7e5f1e48e7eb321644c6fb1668de5
1733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman/* ir-rc5-decoder.c - handle RC5(x) 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/*
16733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman * This code handles 14 bits RC5 protocols and 20 bits RC5x protocols.
17733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman * There are other variants that use a different number of bits.
18733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman * This is currently unsupported.
19733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman * It considers a carrier of 36 kHz, with a total of 14/20 bits, where
209b09df51b8c2b4615376e5ada3e2eb7eeed3cf5dMauro Carvalho Chehab * the first two bits are start bits, and a third one is a filing bit
21db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab */
22db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
233f113e36106f133752de47208816b28aa8e60f88Mauro Carvalho Chehab#include "ir-core-priv.h"
24db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
259b09df51b8c2b4615376e5ada3e2eb7eeed3cf5dMauro Carvalho Chehab#define RC5_NBITS		14
26733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman#define RC5X_NBITS		20
27733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman#define CHECK_RC5X_NBITS	8
28724e2495502a98aaa3f93c404472a991da8ff857David Härdeman#define RC5_UNIT		888888 /* ns */
29e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman#define RC5_BIT_START		(1 * RC5_UNIT)
30e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman#define RC5_BIT_END		(1 * RC5_UNIT)
31e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman#define RC5X_SPACE		(4 * RC5_UNIT)
32db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
33db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab/* Used to register rc5_decoder clients */
34db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehabstatic LIST_HEAD(decoder_list);
356eb9435b874ae5ff56d56952167a8e9be5c5deebMauro Carvalho Chehabstatic DEFINE_SPINLOCK(decoder_lock);
36db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
37db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehabenum rc5_state {
38db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	STATE_INACTIVE,
39724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	STATE_BIT_START,
40724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	STATE_BIT_END,
41733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman	STATE_CHECK_RC5X,
42724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	STATE_FINISHED,
43db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab};
44db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
45db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehabstruct decoder_data {
46db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	struct list_head	list;
47db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	struct ir_input_dev	*ir_dev;
48db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
49db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	/* State machine control */
50db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	enum rc5_state		state;
51724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	u32			rc5_bits;
52e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman	struct ir_raw_event	prev_ev;
53724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	unsigned		count;
54733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman	unsigned		wanted_bits;
55db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab};
56db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
57db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
58db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab/**
59db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab * get_decoder_data()	- gets decoder data
60db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab * @input_dev:	input device
61db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab *
62db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab * Returns the struct decoder_data that corresponds to a device
63db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab */
64db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
65db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehabstatic struct decoder_data *get_decoder_data(struct  ir_input_dev *ir_dev)
66db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab{
67db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	struct decoder_data *data = NULL;
68db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
69db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	spin_lock(&decoder_lock);
70db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	list_for_each_entry(data, &decoder_list, list) {
71db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab		if (data->ir_dev == ir_dev)
72db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab			break;
73db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	}
74db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	spin_unlock(&decoder_lock);
75db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	return data;
76db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab}
77db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
78db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab/**
79724e2495502a98aaa3f93c404472a991da8ff857David Härdeman * ir_rc5_decode() - Decode one RC-5 pulse or space
80db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab * @input_dev:	the struct input_dev descriptor of the device
81e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman * @ev:		the struct ir_raw_event descriptor of the pulse/space
82db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab *
83db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab * This function returns -EINVAL if the pulse violates the state machine
84db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab */
85e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdemanstatic int ir_rc5_decode(struct input_dev *input_dev, struct ir_raw_event ev)
86db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab{
87db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	struct decoder_data *data;
88db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
89733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman	u8 toggle;
90724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	u32 scancode;
91db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
92db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	data = get_decoder_data(ir_dev);
93db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	if (!data)
94db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab		return -EINVAL;
95db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
96667c9ebe97f7e5f1e48e7eb321644c6fb1668de5David Härdeman        if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC5))
97667c9ebe97f7e5f1e48e7eb321644c6fb1668de5David Härdeman                return 0;
987f20d32d446097789ade5ada6b645742ddac4eceMauro Carvalho Chehab
99e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman	if (IS_RESET(ev)) {
100db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab		data->state = STATE_INACTIVE;
101db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab		return 0;
102724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	}
103db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
104e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman	if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
105724e2495502a98aaa3f93c404472a991da8ff857David Härdeman		goto out;
106db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
107724e2495502a98aaa3f93c404472a991da8ff857David Härdemanagain:
108e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman	IR_dprintk(2, "RC5(x) decode started at state %i (%uus %s)\n",
109e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
110db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
111e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman	if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
112724e2495502a98aaa3f93c404472a991da8ff857David Härdeman		return 0;
113db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
114724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	switch (data->state) {
115db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
116724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	case STATE_INACTIVE:
117e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman		if (!ev.pulse)
118e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman			break;
119e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman
120e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman		data->state = STATE_BIT_START;
121e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman		data->count = 1;
122e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman		/* We just need enough bits to get to STATE_CHECK_RC5X */
123e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman		data->wanted_bits = RC5X_NBITS;
124e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman		decrease_duration(&ev, RC5_BIT_START);
125e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman		goto again;
126724e2495502a98aaa3f93c404472a991da8ff857David Härdeman
127724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	case STATE_BIT_START:
128e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman		if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2))
129e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman			break;
130e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman
131e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman		data->rc5_bits <<= 1;
132e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman		if (!ev.pulse)
133e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman			data->rc5_bits |= 1;
134e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman		data->count++;
135e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman		data->prev_ev = ev;
136e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman		data->state = STATE_BIT_END;
137e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman		return 0;
1389b09df51b8c2b4615376e5ada3e2eb7eeed3cf5dMauro Carvalho Chehab
139724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	case STATE_BIT_END:
140e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman		if (!is_transition(&ev, &data->prev_ev))
141e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman			break;
142e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman
143e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman		if (data->count == data->wanted_bits)
144e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman			data->state = STATE_FINISHED;
145e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman		else if (data->count == CHECK_RC5X_NBITS)
146e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman			data->state = STATE_CHECK_RC5X;
147e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman		else
148e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman			data->state = STATE_BIT_START;
149e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman
150e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman		decrease_duration(&ev, RC5_BIT_END);
151e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman		goto again;
152724e2495502a98aaa3f93c404472a991da8ff857David Härdeman
153733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman	case STATE_CHECK_RC5X:
154e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman		if (!ev.pulse && geq_margin(ev.duration, RC5X_SPACE, RC5_UNIT / 2)) {
155733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman			/* RC5X */
156733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman			data->wanted_bits = RC5X_NBITS;
157e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman			decrease_duration(&ev, RC5X_SPACE);
158733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman		} else {
159733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman			/* RC5 */
160733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman			data->wanted_bits = RC5_NBITS;
161733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman		}
162733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman		data->state = STATE_BIT_START;
163733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman		goto again;
164733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman
165724e2495502a98aaa3f93c404472a991da8ff857David Härdeman	case STATE_FINISHED:
166e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman		if (ev.pulse)
167e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman			break;
168e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman
169733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman		if (data->wanted_bits == RC5X_NBITS) {
170733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman			/* RC5X */
171733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman			u8 xdata, command, system;
172733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman			xdata    = (data->rc5_bits & 0x0003F) >> 0;
173733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman			command  = (data->rc5_bits & 0x00FC0) >> 6;
174733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman			system   = (data->rc5_bits & 0x1F000) >> 12;
175733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman			toggle   = (data->rc5_bits & 0x20000) ? 1 : 0;
176733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman			command += (data->rc5_bits & 0x01000) ? 0 : 0x40;
177733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman			scancode = system << 16 | command << 8 | xdata;
178733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman
179733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman			IR_dprintk(1, "RC5X scancode 0x%06x (toggle: %u)\n",
180733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman				   scancode, toggle);
181733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman
182733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman		} else {
183733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman			/* RC5 */
184733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman			u8 command, system;
185733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman			command  = (data->rc5_bits & 0x0003F) >> 0;
186733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman			system   = (data->rc5_bits & 0x007C0) >> 6;
187733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman			toggle   = (data->rc5_bits & 0x00800) ? 1 : 0;
188733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman			command += (data->rc5_bits & 0x01000) ? 0 : 0x40;
189733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman			scancode = system << 8 | command;
190733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman
191733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman			IR_dprintk(1, "RC5 scancode 0x%04x (toggle: %u)\n",
192733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman				   scancode, toggle);
193733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman		}
194733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman
195724e2495502a98aaa3f93c404472a991da8ff857David Härdeman		ir_keydown(input_dev, scancode, toggle);
196db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab		data->state = STATE_INACTIVE;
197db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab		return 0;
198db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	}
199db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
200724e2495502a98aaa3f93c404472a991da8ff857David Härdemanout:
201e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman	IR_dprintk(1, "RC5(x) decode failed at state %i (%uus %s)\n",
202e40b1127f994a427568319d1be9b9e5ab1f58dd1David Härdeman		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
203db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	data->state = STATE_INACTIVE;
204db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	return -EINVAL;
205db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab}
206db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
207db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehabstatic int ir_rc5_register(struct input_dev *input_dev)
208db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab{
209db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
210db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	struct decoder_data *data;
211db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
212db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	data = kzalloc(sizeof(*data), GFP_KERNEL);
213667c9ebe97f7e5f1e48e7eb321644c6fb1668de5David Härdeman	if (!data)
214db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab		return -ENOMEM;
215db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
216db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	data->ir_dev = ir_dev;
217db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
218db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	spin_lock(&decoder_lock);
219db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	list_add_tail(&data->list, &decoder_list);
220db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	spin_unlock(&decoder_lock);
221db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
222db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	return 0;
223db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab}
224db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
225db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehabstatic int ir_rc5_unregister(struct input_dev *input_dev)
226db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab{
227db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
228db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	static struct decoder_data *data;
229db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
230db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	data = get_decoder_data(ir_dev);
231db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	if (!data)
232db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab		return 0;
233db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
234db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	spin_lock(&decoder_lock);
235db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	list_del(&data->list);
236db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	spin_unlock(&decoder_lock);
237db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
238db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	return 0;
239db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab}
240db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
241db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehabstatic struct ir_raw_handler rc5_handler = {
242667c9ebe97f7e5f1e48e7eb321644c6fb1668de5David Härdeman	.protocols	= IR_TYPE_RC5,
243db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	.decode		= ir_rc5_decode,
244db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	.raw_register	= ir_rc5_register,
245db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	.raw_unregister	= ir_rc5_unregister,
246db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab};
247db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
248db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehabstatic int __init ir_rc5_decode_init(void)
249db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab{
250db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	ir_raw_handler_register(&rc5_handler);
251db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
252733419b5c4d29186006982a9a27227e214a39dbcDavid Härdeman	printk(KERN_INFO "IR RC5(x) protocol handler initialized\n");
253db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	return 0;
254db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab}
255db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
256db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehabstatic void __exit ir_rc5_decode_exit(void)
257db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab{
258db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab	ir_raw_handler_unregister(&rc5_handler);
259db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab}
260db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
261db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehabmodule_init(ir_rc5_decode_init);
262db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehabmodule_exit(ir_rc5_decode_exit);
263db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho Chehab
264db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho ChehabMODULE_LICENSE("GPL");
265db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho ChehabMODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
266db1423a6c79f66db2b1846614c13bde9c2db7ad2Mauro Carvalho ChehabMODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
267733419b5c4d29186006982a9a27227e214a39dbcDavid HärdemanMODULE_DESCRIPTION("RC5(x) IR protocol decoder");
268