Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c216369e authored by David Härdeman's avatar David Härdeman Committed by Mauro Carvalho Chehab
Browse files

V4L/DVB: ir-core: move decoding state to ir_raw_event_ctrl



This patch moves the state from each raw decoder into the
ir_raw_event_ctrl struct.

This allows the removal of code like this:

        spin_lock(&decoder_lock);
        list_for_each_entry(data, &decoder_list, list) {
                if (data->ir_dev == ir_dev)
                        break;
        }
        spin_unlock(&decoder_lock);
        return data;

which is currently run for each decoder on each event in order
to get the client-specific decoding state data.

In addition, ir decoding modules and ir driver module load
order is now independent. Centralizing the data also allows
for a nice code reduction of about 30% per raw decoder as
client lists and client registration callbacks are no longer
necessary (but still kept around for the benefit of the lirc
decoder).

Out-of-tree modules can still use a similar trick to what
the raw decoders did before this patch until they are merged.

Signed-off-by: default avatarDavid Härdeman <david@hardeman.nu>
Acked-by: default avatarJarod Wilson <jarod@redhat.com>
Tested-by: default avatarJarod Wilson <jarod@redhat.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent de8592bd
Loading
Loading
Loading
Loading
+38 −0
Original line number Diff line number Diff line
@@ -24,17 +24,55 @@ struct ir_raw_handler {

	u64 protocols; /* which are handled by this handler */
	int (*decode)(struct input_dev *input_dev, struct ir_raw_event event);

	/* These two should only be used by the lirc decoder */
	int (*raw_register)(struct input_dev *input_dev);
	int (*raw_unregister)(struct input_dev *input_dev);
};

struct ir_raw_event_ctrl {
	struct list_head		list;		/* to keep track of raw clients */
	struct work_struct		rx_work;	/* for the rx decoding workqueue */
	struct kfifo			kfifo;		/* fifo for the pulse/space durations */
	ktime_t				last_event;	/* when last event occurred */
	enum raw_event_type		last_type;	/* last event type */
	struct input_dev		*input_dev;	/* pointer to the parent input_dev */
	u64				enabled_protocols; /* enabled raw protocol decoders */

	/* raw decoder state follows */
	struct ir_raw_event prev_ev;
	struct nec_dec {
		int state;
		unsigned count;
		u32 bits;
	} nec;
	struct rc5_dec {
		int state;
		u32 bits;
		unsigned count;
		unsigned wanted_bits;
	} rc5;
	struct rc6_dec {
		int state;
		u8 header;
		u32 body;
		bool toggle;
		unsigned count;
		unsigned wanted_bits;
	} rc6;
	struct sony_dec {
		int state;
		u32 bits;
		unsigned count;
	} sony;
	struct jvc_dec {
		int state;
		u16 bits;
		u16 old_bits;
		unsigned count;
		bool first;
		bool toggle;
	} jvc;
};

/* macros for IR decoders */
+7 −84
Original line number Diff line number Diff line
@@ -25,10 +25,6 @@
#define JVC_TRAILER_PULSE	(1  * JVC_UNIT)
#define	JVC_TRAILER_SPACE	(35 * JVC_UNIT)

/* Used to register jvc_decoder clients */
static LIST_HEAD(decoder_list);
DEFINE_SPINLOCK(decoder_lock);

enum jvc_state {
	STATE_INACTIVE,
	STATE_HEADER_SPACE,
@@ -38,39 +34,6 @@ enum jvc_state {
	STATE_TRAILER_SPACE,
};

struct decoder_data {
	struct list_head	list;
	struct ir_input_dev	*ir_dev;

	/* State machine control */
	enum jvc_state		state;
	u16			jvc_bits;
	u16			jvc_old_bits;
	unsigned		count;
	bool			first;
	bool			toggle;
};


/**
 * get_decoder_data()	- gets decoder data
 * @input_dev:	input device
 *
 * Returns the struct decoder_data that corresponds to a device
 */
static struct decoder_data *get_decoder_data(struct  ir_input_dev *ir_dev)
{
	struct decoder_data *data = NULL;

	spin_lock(&decoder_lock);
	list_for_each_entry(data, &decoder_list, list) {
		if (data->ir_dev == ir_dev)
			break;
	}
	spin_unlock(&decoder_lock);
	return data;
}

/**
 * ir_jvc_decode() - Decode one JVC pulse or space
 * @input_dev:	the struct input_dev descriptor of the device
@@ -80,12 +43,8 @@ static struct decoder_data *get_decoder_data(struct ir_input_dev *ir_dev)
 */
static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
{
	struct decoder_data *data;
	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);

	data = get_decoder_data(ir_dev);
	if (!data)
		return -EINVAL;
	struct jvc_dec *data = &ir_dev->raw->jvc;

	if (!(ir_dev->raw->enabled_protocols & IR_TYPE_JVC))
		return 0;
@@ -140,9 +99,9 @@ static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
		if (ev.pulse)
			break;

		data->jvc_bits <<= 1;
		data->bits <<= 1;
		if (eq_margin(ev.duration, JVC_BIT_1_SPACE, JVC_UNIT / 2)) {
			data->jvc_bits |= 1;
			data->bits |= 1;
			decrease_duration(&ev, JVC_BIT_1_SPACE);
		} else if (eq_margin(ev.duration, JVC_BIT_0_SPACE, JVC_UNIT / 2))
			decrease_duration(&ev, JVC_BIT_0_SPACE);
@@ -175,13 +134,13 @@ static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev)

		if (data->first) {
			u32 scancode;
			scancode = (bitrev8((data->jvc_bits >> 8) & 0xff) << 8) |
				   (bitrev8((data->jvc_bits >> 0) & 0xff) << 0);
			scancode = (bitrev8((data->bits >> 8) & 0xff) << 8) |
				   (bitrev8((data->bits >> 0) & 0xff) << 0);
			IR_dprintk(1, "JVC scancode 0x%04x\n", scancode);
			ir_keydown(input_dev, scancode, data->toggle);
			data->first = false;
			data->jvc_old_bits = data->jvc_bits;
		} else if (data->jvc_bits == data->jvc_old_bits) {
			data->old_bits = data->bits;
		} else if (data->bits == data->old_bits) {
			IR_dprintk(1, "JVC repeat\n");
			ir_repeat(input_dev);
		} else {
@@ -201,45 +160,9 @@ out:
	return -EINVAL;
}

static int ir_jvc_register(struct input_dev *input_dev)
{
	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
	struct decoder_data *data;

	data = kzalloc(sizeof(*data), GFP_KERNEL);
	if (!data)
		return -ENOMEM;

	data->ir_dev = ir_dev;

	spin_lock(&decoder_lock);
	list_add_tail(&data->list, &decoder_list);
	spin_unlock(&decoder_lock);

	return 0;
}

static int ir_jvc_unregister(struct input_dev *input_dev)
{
	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
	static struct decoder_data *data;

	data = get_decoder_data(ir_dev);
	if (!data)
		return 0;

	spin_lock(&decoder_lock);
	list_del(&data->list);
	spin_unlock(&decoder_lock);

	return 0;
}

static struct ir_raw_handler jvc_handler = {
	.protocols	= IR_TYPE_JVC,
	.decode		= ir_jvc_decode,
	.raw_register	= ir_jvc_register,
	.raw_unregister	= ir_jvc_unregister,
};

static int __init ir_jvc_decode_init(void)
+8 −82
Original line number Diff line number Diff line
@@ -27,10 +27,6 @@
#define	NEC_TRAILER_PULSE	(1  * NEC_UNIT)
#define	NEC_TRAILER_SPACE	(10 * NEC_UNIT) /* even longer in reality */

/* Used to register nec_decoder clients */
static LIST_HEAD(decoder_list);
static DEFINE_SPINLOCK(decoder_lock);

enum nec_state {
	STATE_INACTIVE,
	STATE_HEADER_SPACE,
@@ -40,36 +36,6 @@ enum nec_state {
	STATE_TRAILER_SPACE,
};

struct decoder_data {
	struct list_head	list;
	struct ir_input_dev	*ir_dev;

	/* State machine control */
	enum nec_state		state;
	u32			nec_bits;
	unsigned		count;
};


/**
 * get_decoder_data()	- gets decoder data
 * @input_dev:	input device
 *
 * Returns the struct decoder_data that corresponds to a device
 */
static struct decoder_data *get_decoder_data(struct  ir_input_dev *ir_dev)
{
	struct decoder_data *data = NULL;

	spin_lock(&decoder_lock);
	list_for_each_entry(data, &decoder_list, list) {
		if (data->ir_dev == ir_dev)
			break;
	}
	spin_unlock(&decoder_lock);
	return data;
}

/**
 * ir_nec_decode() - Decode one NEC pulse or space
 * @input_dev:	the struct input_dev descriptor of the device
@@ -79,15 +45,11 @@ static struct decoder_data *get_decoder_data(struct ir_input_dev *ir_dev)
 */
static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
{
	struct decoder_data *data;
	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
	struct nec_dec *data = &ir_dev->raw->nec;
	u32 scancode;
	u8 address, not_address, command, not_command;

	data = get_decoder_data(ir_dev);
	if (!data)
		return -EINVAL;

	if (!(ir_dev->raw->enabled_protocols & IR_TYPE_NEC))
		return 0;

@@ -143,9 +105,9 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
		if (ev.pulse)
			break;

		data->nec_bits <<= 1;
		data->bits <<= 1;
		if (eq_margin(ev.duration, NEC_BIT_1_SPACE, NEC_UNIT / 2))
			data->nec_bits |= 1;
			data->bits |= 1;
		else if (!eq_margin(ev.duration, NEC_BIT_0_SPACE, NEC_UNIT / 2))
			break;
		data->count++;
@@ -174,14 +136,14 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
		if (!geq_margin(ev.duration, NEC_TRAILER_SPACE, NEC_UNIT / 2))
			break;

		address     = bitrev8((data->nec_bits >> 24) & 0xff);
		not_address = bitrev8((data->nec_bits >> 16) & 0xff);
		command	    = bitrev8((data->nec_bits >>  8) & 0xff);
		not_command = bitrev8((data->nec_bits >>  0) & 0xff);
		address     = bitrev8((data->bits >> 24) & 0xff);
		not_address = bitrev8((data->bits >> 16) & 0xff);
		command	    = bitrev8((data->bits >>  8) & 0xff);
		not_command = bitrev8((data->bits >>  0) & 0xff);

		if ((command ^ not_command) != 0xff) {
			IR_dprintk(1, "NEC checksum error: received 0x%08x\n",
				   data->nec_bits);
				   data->bits);
			break;
		}

@@ -208,45 +170,9 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
	return -EINVAL;
}

static int ir_nec_register(struct input_dev *input_dev)
{
	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
	struct decoder_data *data;

	data = kzalloc(sizeof(*data), GFP_KERNEL);
	if (!data)
		return -ENOMEM;

	data->ir_dev = ir_dev;

	spin_lock(&decoder_lock);
	list_add_tail(&data->list, &decoder_list);
	spin_unlock(&decoder_lock);

	return 0;
}

static int ir_nec_unregister(struct input_dev *input_dev)
{
	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
	static struct decoder_data *data;

	data = get_decoder_data(ir_dev);
	if (!data)
		return 0;

	spin_lock(&decoder_lock);
	list_del(&data->list);
	spin_unlock(&decoder_lock);

	return 0;
}

static struct ir_raw_handler nec_handler = {
	.protocols	= IR_TYPE_NEC,
	.decode		= ir_nec_decode,
	.raw_register	= ir_nec_register,
	.raw_unregister	= ir_nec_unregister,
};

static int __init ir_nec_decode_init(void)
+37 −36
Original line number Diff line number Diff line
@@ -20,36 +20,14 @@
/* Define the max number of pulse/space transitions to buffer */
#define MAX_IR_EVENT_SIZE      512

/* Used to keep track of IR raw clients, protected by ir_raw_handler_lock */
static LIST_HEAD(ir_raw_client_list);

/* Used to handle IR raw handler extensions */
static DEFINE_SPINLOCK(ir_raw_handler_lock);
static LIST_HEAD(ir_raw_handler_list);
static u64 available_protocols;

/**
 * RUN_DECODER()	- runs an operation on all IR decoders
 * @ops:	IR raw handler operation to be called
 * @arg:	arguments to be passed to the callback
 *
 * Calls ir_raw_handler::ops for all registered IR handlers. It prevents
 * new decode addition/removal while running, by locking ir_raw_handler_lock
 * mutex. If an error occurs, we keep going, as in the decode case, each
 * decoder must have a crack at decoding the data. We return a sum of the
 * return codes, which will be either 0 or negative for current callers.
 */
#define RUN_DECODER(ops, ...) ({					    \
	struct ir_raw_handler		*_ir_raw_handler;		    \
	int _sumrc = 0, _rc;						    \
	spin_lock(&ir_raw_handler_lock);				    \
	list_for_each_entry(_ir_raw_handler, &ir_raw_handler_list, list) {  \
		if (_ir_raw_handler->ops) {				    \
			_rc = _ir_raw_handler->ops(__VA_ARGS__);	    \
			_sumrc += _rc;					    \
		}							    \
	}								    \
	spin_unlock(&ir_raw_handler_lock);				    \
	_sumrc;								    \
})

#ifdef MODULE
/* Used to load the decoders */
static struct work_struct wq_load;
@@ -58,11 +36,17 @@ static struct work_struct wq_load;
static void ir_raw_event_work(struct work_struct *work)
{
	struct ir_raw_event ev;
	struct ir_raw_handler *handler;
	struct ir_raw_event_ctrl *raw =
		container_of(work, struct ir_raw_event_ctrl, rx_work);

	while (kfifo_out(&raw->kfifo, &ev, sizeof(ev)) == sizeof(ev))
		RUN_DECODER(decode, raw->input_dev, ev);
	while (kfifo_out(&raw->kfifo, &ev, sizeof(ev)) == sizeof(ev)) {
		spin_lock(&ir_raw_handler_lock);
		list_for_each_entry(handler, &ir_raw_handler_list, list)
			handler->decode(raw->input_dev, ev);
		spin_unlock(&ir_raw_handler_lock);
		raw->prev_ev = ev;
	}
}

/**
@@ -176,6 +160,7 @@ int ir_raw_event_register(struct input_dev *input_dev)
{
	struct ir_input_dev *ir = input_get_drvdata(input_dev);
	int rc;
	struct ir_raw_handler *handler;

	ir->raw = kzalloc(sizeof(*ir->raw), GFP_KERNEL);
	if (!ir->raw)
@@ -192,26 +177,32 @@ int ir_raw_event_register(struct input_dev *input_dev)
		return rc;
	}

	rc = RUN_DECODER(raw_register, input_dev);
	if (rc < 0) {
		kfifo_free(&ir->raw->kfifo);
		kfree(ir->raw);
		ir->raw = NULL;
		return rc;
	}
	spin_lock(&ir_raw_handler_lock);
	list_add_tail(&ir->raw->list, &ir_raw_client_list);
	list_for_each_entry(handler, &ir_raw_handler_list, list)
		if (handler->raw_register)
			handler->raw_register(ir->raw->input_dev);
	spin_unlock(&ir_raw_handler_lock);

	return rc;
	return 0;
}

void ir_raw_event_unregister(struct input_dev *input_dev)
{
	struct ir_input_dev *ir = input_get_drvdata(input_dev);
	struct ir_raw_handler *handler;

	if (!ir->raw)
		return;

	cancel_work_sync(&ir->raw->rx_work);
	RUN_DECODER(raw_unregister, input_dev);

	spin_lock(&ir_raw_handler_lock);
	list_del(&ir->raw->list);
	list_for_each_entry(handler, &ir_raw_handler_list, list)
		if (handler->raw_unregister)
			handler->raw_unregister(ir->raw->input_dev);
	spin_unlock(&ir_raw_handler_lock);

	kfifo_free(&ir->raw->kfifo);
	kfree(ir->raw);
@@ -224,8 +215,13 @@ void ir_raw_event_unregister(struct input_dev *input_dev)

int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler)
{
	struct ir_raw_event_ctrl *raw;

	spin_lock(&ir_raw_handler_lock);
	list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list);
	if (ir_raw_handler->raw_register)
		list_for_each_entry(raw, &ir_raw_client_list, list)
			ir_raw_handler->raw_register(raw->input_dev);
	available_protocols |= ir_raw_handler->protocols;
	spin_unlock(&ir_raw_handler_lock);

@@ -235,8 +231,13 @@ EXPORT_SYMBOL(ir_raw_handler_register);

void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
{
	struct ir_raw_event_ctrl *raw;

	spin_lock(&ir_raw_handler_lock);
	list_del(&ir_raw_handler->list);
	if (ir_raw_handler->raw_unregister)
		list_for_each_entry(raw, &ir_raw_client_list, list)
			ir_raw_handler->raw_unregister(raw->input_dev);
	available_protocols &= ~ir_raw_handler->protocols;
	spin_unlock(&ir_raw_handler_lock);
}
+13 −91
Original line number Diff line number Diff line
@@ -30,10 +30,6 @@
#define RC5_BIT_END		(1 * RC5_UNIT)
#define RC5X_SPACE		(4 * RC5_UNIT)

/* Used to register rc5_decoder clients */
static LIST_HEAD(decoder_list);
static DEFINE_SPINLOCK(decoder_lock);

enum rc5_state {
	STATE_INACTIVE,
	STATE_BIT_START,
@@ -42,39 +38,6 @@ enum rc5_state {
	STATE_FINISHED,
};

struct decoder_data {
	struct list_head	list;
	struct ir_input_dev	*ir_dev;

	/* State machine control */
	enum rc5_state		state;
	u32			rc5_bits;
	struct ir_raw_event	prev_ev;
	unsigned		count;
	unsigned		wanted_bits;
};


/**
 * get_decoder_data()	- gets decoder data
 * @input_dev:	input device
 *
 * Returns the struct decoder_data that corresponds to a device
 */

static struct decoder_data *get_decoder_data(struct  ir_input_dev *ir_dev)
{
	struct decoder_data *data = NULL;

	spin_lock(&decoder_lock);
	list_for_each_entry(data, &decoder_list, list) {
		if (data->ir_dev == ir_dev)
			break;
	}
	spin_unlock(&decoder_lock);
	return data;
}

/**
 * ir_rc5_decode() - Decode one RC-5 pulse or space
 * @input_dev:	the struct input_dev descriptor of the device
@@ -84,15 +47,11 @@ static struct decoder_data *get_decoder_data(struct ir_input_dev *ir_dev)
 */
static int ir_rc5_decode(struct input_dev *input_dev, struct ir_raw_event ev)
{
	struct decoder_data *data;
	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
	struct rc5_dec *data = &ir_dev->raw->rc5;
	u8 toggle;
	u32 scancode;

	data = get_decoder_data(ir_dev);
	if (!data)
		return -EINVAL;

        if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC5))
                return 0;

@@ -128,16 +87,15 @@ again:
		if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2))
			break;

		data->rc5_bits <<= 1;
		data->bits <<= 1;
		if (!ev.pulse)
			data->rc5_bits |= 1;
			data->bits |= 1;
		data->count++;
		data->prev_ev = ev;
		data->state = STATE_BIT_END;
		return 0;

	case STATE_BIT_END:
		if (!is_transition(&ev, &data->prev_ev))
		if (!is_transition(&ev, &ir_dev->raw->prev_ev))
			break;

		if (data->count == data->wanted_bits)
@@ -169,11 +127,11 @@ again:
		if (data->wanted_bits == RC5X_NBITS) {
			/* RC5X */
			u8 xdata, command, system;
			xdata    = (data->rc5_bits & 0x0003F) >> 0;
			command  = (data->rc5_bits & 0x00FC0) >> 6;
			system   = (data->rc5_bits & 0x1F000) >> 12;
			toggle   = (data->rc5_bits & 0x20000) ? 1 : 0;
			command += (data->rc5_bits & 0x01000) ? 0 : 0x40;
			xdata    = (data->bits & 0x0003F) >> 0;
			command  = (data->bits & 0x00FC0) >> 6;
			system   = (data->bits & 0x1F000) >> 12;
			toggle   = (data->bits & 0x20000) ? 1 : 0;
			command += (data->bits & 0x01000) ? 0 : 0x40;
			scancode = system << 16 | command << 8 | xdata;

			IR_dprintk(1, "RC5X scancode 0x%06x (toggle: %u)\n",
@@ -182,10 +140,10 @@ again:
		} else {
			/* RC5 */
			u8 command, system;
			command  = (data->rc5_bits & 0x0003F) >> 0;
			system   = (data->rc5_bits & 0x007C0) >> 6;
			toggle   = (data->rc5_bits & 0x00800) ? 1 : 0;
			command += (data->rc5_bits & 0x01000) ? 0 : 0x40;
			command  = (data->bits & 0x0003F) >> 0;
			system   = (data->bits & 0x007C0) >> 6;
			toggle   = (data->bits & 0x00800) ? 1 : 0;
			command += (data->bits & 0x01000) ? 0 : 0x40;
			scancode = system << 8 | command;

			IR_dprintk(1, "RC5 scancode 0x%04x (toggle: %u)\n",
@@ -204,45 +162,9 @@ out:
	return -EINVAL;
}

static int ir_rc5_register(struct input_dev *input_dev)
{
	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
	struct decoder_data *data;

	data = kzalloc(sizeof(*data), GFP_KERNEL);
	if (!data)
		return -ENOMEM;

	data->ir_dev = ir_dev;

	spin_lock(&decoder_lock);
	list_add_tail(&data->list, &decoder_list);
	spin_unlock(&decoder_lock);

	return 0;
}

static int ir_rc5_unregister(struct input_dev *input_dev)
{
	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
	static struct decoder_data *data;

	data = get_decoder_data(ir_dev);
	if (!data)
		return 0;

	spin_lock(&decoder_lock);
	list_del(&data->list);
	spin_unlock(&decoder_lock);

	return 0;
}

static struct ir_raw_handler rc5_handler = {
	.protocols	= IR_TYPE_RC5,
	.decode		= ir_rc5_decode,
	.raw_register	= ir_rc5_register,
	.raw_unregister	= ir_rc5_unregister,
};

static int __init ir_rc5_decode_init(void)
Loading