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