ir-sony-decoder.c (5921B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* ir-sony-decoder.c - handle Sony IR Pulse/Space protocol 3 * 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 space 29 * @dev: the struct rc_dev descriptor of the device 30 * @ev: the struct ir_raw_event descriptor of the pulse/space 31 * 32 * This function returns -EINVAL if the pulse violates the state machine 33 */ 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 events 177 * 178 * @protocol: protocol to encode 179 * @scancode: scancode to encode 180 * @events: array of raw ir events to write into 181 * @max: maximum size of @events 182 * 183 * Returns: The number of events written. 184 * -ENOBUFS if there isn't enough space in the array to fit the 185 * 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");