brintos

brintos / linux-shallow public Read only

0
0
Text · 5.8 KiB · bb25867 Raw
241 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* ir-sony-decoder.c - handle Sony IR Pulse/Space protocol3 *4 * Copyright (C) 2010 by David Härdeman <david@hardeman.nu>5 */6 7#include <linux/bitrev.h>8#include <linux/module.h>9#include "rc-core-priv.h"10 11#define SONY_UNIT		600 /* us */12#define SONY_HEADER_PULSE	(4 * SONY_UNIT)13#define	SONY_HEADER_SPACE	(1 * SONY_UNIT)14#define SONY_BIT_0_PULSE	(1 * SONY_UNIT)15#define SONY_BIT_1_PULSE	(2 * SONY_UNIT)16#define SONY_BIT_SPACE		(1 * SONY_UNIT)17#define SONY_TRAILER_SPACE	(10 * SONY_UNIT) /* minimum */18 19enum sony_state {20	STATE_INACTIVE,21	STATE_HEADER_SPACE,22	STATE_BIT_PULSE,23	STATE_BIT_SPACE,24	STATE_FINISHED,25};26 27/**28 * ir_sony_decode() - Decode one Sony pulse or space29 * @dev:	the struct rc_dev descriptor of the device30 * @ev:         the struct ir_raw_event descriptor of the pulse/space31 *32 * This function returns -EINVAL if the pulse violates the state machine33 */34static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)35{36	struct sony_dec *data = &dev->raw->sony;37	enum rc_proto protocol;38	u32 scancode;39	u8 device, subdevice, function;40 41	if (!is_timing_event(ev)) {42		if (ev.overflow)43			data->state = STATE_INACTIVE;44		return 0;45	}46 47	if (!geq_margin(ev.duration, SONY_UNIT, SONY_UNIT / 2))48		goto out;49 50	dev_dbg(&dev->dev, "Sony decode started at state %d (%uus %s)\n",51		data->state, ev.duration, TO_STR(ev.pulse));52 53	switch (data->state) {54 55	case STATE_INACTIVE:56		if (!ev.pulse)57			break;58 59		if (!eq_margin(ev.duration, SONY_HEADER_PULSE, SONY_UNIT / 2))60			break;61 62		data->count = 0;63		data->state = STATE_HEADER_SPACE;64		return 0;65 66	case STATE_HEADER_SPACE:67		if (ev.pulse)68			break;69 70		if (!eq_margin(ev.duration, SONY_HEADER_SPACE, SONY_UNIT / 2))71			break;72 73		data->state = STATE_BIT_PULSE;74		return 0;75 76	case STATE_BIT_PULSE:77		if (!ev.pulse)78			break;79 80		data->bits <<= 1;81		if (eq_margin(ev.duration, SONY_BIT_1_PULSE, SONY_UNIT / 2))82			data->bits |= 1;83		else if (!eq_margin(ev.duration, SONY_BIT_0_PULSE, SONY_UNIT / 2))84			break;85 86		data->count++;87		data->state = STATE_BIT_SPACE;88		return 0;89 90	case STATE_BIT_SPACE:91		if (ev.pulse)92			break;93 94		if (!geq_margin(ev.duration, SONY_BIT_SPACE, SONY_UNIT / 2))95			break;96 97		decrease_duration(&ev, SONY_BIT_SPACE);98 99		if (!geq_margin(ev.duration, SONY_UNIT, SONY_UNIT / 2)) {100			data->state = STATE_BIT_PULSE;101			return 0;102		}103 104		data->state = STATE_FINISHED;105		fallthrough;106 107	case STATE_FINISHED:108		if (ev.pulse)109			break;110 111		if (!geq_margin(ev.duration, SONY_TRAILER_SPACE, SONY_UNIT / 2))112			break;113 114		switch (data->count) {115		case 12:116			if (!(dev->enabled_protocols & RC_PROTO_BIT_SONY12))117				goto finish_state_machine;118 119			device    = bitrev8((data->bits <<  3) & 0xF8);120			subdevice = 0;121			function  = bitrev8((data->bits >>  4) & 0xFE);122			protocol = RC_PROTO_SONY12;123			break;124		case 15:125			if (!(dev->enabled_protocols & RC_PROTO_BIT_SONY15))126				goto finish_state_machine;127 128			device    = bitrev8((data->bits >>  0) & 0xFF);129			subdevice = 0;130			function  = bitrev8((data->bits >>  7) & 0xFE);131			protocol = RC_PROTO_SONY15;132			break;133		case 20:134			if (!(dev->enabled_protocols & RC_PROTO_BIT_SONY20))135				goto finish_state_machine;136 137			device    = bitrev8((data->bits >>  5) & 0xF8);138			subdevice = bitrev8((data->bits >>  0) & 0xFF);139			function  = bitrev8((data->bits >> 12) & 0xFE);140			protocol = RC_PROTO_SONY20;141			break;142		default:143			dev_dbg(&dev->dev, "Sony invalid bitcount %u\n",144				data->count);145			goto out;146		}147 148		scancode = device << 16 | subdevice << 8 | function;149		dev_dbg(&dev->dev, "Sony(%u) scancode 0x%05x\n", data->count,150			scancode);151		rc_keydown(dev, protocol, scancode, 0);152		goto finish_state_machine;153	}154 155out:156	dev_dbg(&dev->dev, "Sony decode failed at state %d (%uus %s)\n",157		data->state, ev.duration, TO_STR(ev.pulse));158	data->state = STATE_INACTIVE;159	return -EINVAL;160 161finish_state_machine:162	data->state = STATE_INACTIVE;163	return 0;164}165 166static const struct ir_raw_timings_pl ir_sony_timings = {167	.header_pulse  = SONY_HEADER_PULSE,168	.bit_space     = SONY_BIT_SPACE,169	.bit_pulse[0]  = SONY_BIT_0_PULSE,170	.bit_pulse[1]  = SONY_BIT_1_PULSE,171	.trailer_space = SONY_TRAILER_SPACE + SONY_BIT_SPACE,172	.msb_first     = 0,173};174 175/**176 * ir_sony_encode() - Encode a scancode as a stream of raw events177 *178 * @protocol:	protocol to encode179 * @scancode:	scancode to encode180 * @events:	array of raw ir events to write into181 * @max:	maximum size of @events182 *183 * Returns:	The number of events written.184 *		-ENOBUFS if there isn't enough space in the array to fit the185 *		encoding. In this case all @max events will have been written.186 */187static int ir_sony_encode(enum rc_proto protocol, u32 scancode,188			  struct ir_raw_event *events, unsigned int max)189{190	struct ir_raw_event *e = events;191	u32 raw, len;192	int ret;193 194	if (protocol == RC_PROTO_SONY12) {195		raw = (scancode & 0x7f) | ((scancode & 0x1f0000) >> 9);196		len = 12;197	} else if (protocol == RC_PROTO_SONY15) {198		raw = (scancode & 0x7f) | ((scancode & 0xff0000) >> 9);199		len = 15;200	} else {201		raw = (scancode & 0x7f) | ((scancode & 0x1f0000) >> 9) |202		       ((scancode & 0xff00) << 4);203		len = 20;204	}205 206	ret = ir_raw_gen_pl(&e, max, &ir_sony_timings, len, raw);207	if (ret < 0)208		return ret;209 210	return e - events;211}212 213static struct ir_raw_handler sony_handler = {214	.protocols	= RC_PROTO_BIT_SONY12 | RC_PROTO_BIT_SONY15 |215							RC_PROTO_BIT_SONY20,216	.decode		= ir_sony_decode,217	.encode		= ir_sony_encode,218	.carrier	= 40000,219	.min_timeout	= SONY_TRAILER_SPACE,220};221 222static int __init ir_sony_decode_init(void)223{224	ir_raw_handler_register(&sony_handler);225 226	printk(KERN_INFO "IR Sony protocol handler initialized\n");227	return 0;228}229 230static void __exit ir_sony_decode_exit(void)231{232	ir_raw_handler_unregister(&sony_handler);233}234 235module_init(ir_sony_decode_init);236module_exit(ir_sony_decode_exit);237 238MODULE_LICENSE("GPL");239MODULE_AUTHOR("David Härdeman <david@hardeman.nu>");240MODULE_DESCRIPTION("Sony IR protocol decoder");241