root/drivers/media/rc/ir-rcmm-decoder.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rcmm_mode
  2. rcmm_miscmode
  3. ir_rcmm_decode
  4. ir_rcmm_rawencoder
  5. ir_rcmm_encode
  6. ir_rcmm_decode_init
  7. ir_rcmm_decode_exit

   1 // SPDX-License-Identifier: GPL-2.0+
   2 // ir-rcmm-decoder.c - A decoder for the RCMM IR protocol
   3 //
   4 // Copyright (C) 2018 by Patrick Lerda <patrick9876@free.fr>
   5 
   6 #include "rc-core-priv.h"
   7 #include <linux/module.h>
   8 
   9 #define RCMM_UNIT               166667  /* nanosecs */
  10 #define RCMM_PREFIX_PULSE       416666  /* 166666.666666666*2.5 */
  11 #define RCMM_PULSE_0            277777  /* 166666.666666666*(1+2/3) */
  12 #define RCMM_PULSE_1            444444  /* 166666.666666666*(2+2/3) */
  13 #define RCMM_PULSE_2            611111  /* 166666.666666666*(3+2/3) */
  14 #define RCMM_PULSE_3            777778  /* 166666.666666666*(4+2/3) */
  15 
  16 enum rcmm_state {
  17         STATE_INACTIVE,
  18         STATE_LOW,
  19         STATE_BUMP,
  20         STATE_VALUE,
  21         STATE_FINISHED,
  22 };
  23 
  24 static bool rcmm_mode(const struct rcmm_dec *data)
  25 {
  26         return !((0x000c0000 & data->bits) == 0x000c0000);
  27 }
  28 
  29 static int rcmm_miscmode(struct rc_dev *dev, struct rcmm_dec *data)
  30 {
  31         switch (data->count) {
  32         case 24:
  33                 if (dev->enabled_protocols & RC_PROTO_BIT_RCMM24) {
  34                         rc_keydown(dev, RC_PROTO_RCMM24, data->bits, 0);
  35                         data->state = STATE_INACTIVE;
  36                         return 0;
  37                 }
  38                 return -1;
  39 
  40         case 12:
  41                 if (dev->enabled_protocols & RC_PROTO_BIT_RCMM12) {
  42                         rc_keydown(dev, RC_PROTO_RCMM12, data->bits, 0);
  43                         data->state = STATE_INACTIVE;
  44                         return 0;
  45                 }
  46                 return -1;
  47         }
  48 
  49         return -1;
  50 }
  51 
  52 /**
  53  * ir_rcmm_decode() - Decode one RCMM pulse or space
  54  * @dev:        the struct rc_dev descriptor of the device
  55  * @ev:         the struct ir_raw_event descriptor of the pulse/space
  56  *
  57  * This function returns -EINVAL if the pulse violates the state machine
  58  */
  59 static int ir_rcmm_decode(struct rc_dev *dev, struct ir_raw_event ev)
  60 {
  61         struct rcmm_dec *data = &dev->raw->rcmm;
  62         u32 scancode;
  63         u8 toggle;
  64         int value;
  65 
  66         if (!(dev->enabled_protocols & (RC_PROTO_BIT_RCMM32 |
  67                                                         RC_PROTO_BIT_RCMM24 |
  68                                                         RC_PROTO_BIT_RCMM12)))
  69                 return 0;
  70 
  71         if (!is_timing_event(ev)) {
  72                 if (ev.reset)
  73                         data->state = STATE_INACTIVE;
  74                 return 0;
  75         }
  76 
  77         switch (data->state) {
  78         case STATE_INACTIVE:
  79                 if (!ev.pulse)
  80                         break;
  81 
  82                 if (!eq_margin(ev.duration, RCMM_PREFIX_PULSE, RCMM_UNIT / 2))
  83                         break;
  84 
  85                 data->state = STATE_LOW;
  86                 data->count = 0;
  87                 data->bits  = 0;
  88                 return 0;
  89 
  90         case STATE_LOW:
  91                 if (ev.pulse)
  92                         break;
  93 
  94                 if (!eq_margin(ev.duration, RCMM_PULSE_0, RCMM_UNIT / 2))
  95                         break;
  96 
  97                 data->state = STATE_BUMP;
  98                 return 0;
  99 
 100         case STATE_BUMP:
 101                 if (!ev.pulse)
 102                         break;
 103 
 104                 if (!eq_margin(ev.duration, RCMM_UNIT, RCMM_UNIT / 2))
 105                         break;
 106 
 107                 data->state = STATE_VALUE;
 108                 return 0;
 109 
 110         case STATE_VALUE:
 111                 if (ev.pulse)
 112                         break;
 113 
 114                 if (eq_margin(ev.duration, RCMM_PULSE_0, RCMM_UNIT / 2))
 115                         value = 0;
 116                 else if (eq_margin(ev.duration, RCMM_PULSE_1, RCMM_UNIT / 2))
 117                         value = 1;
 118                 else if (eq_margin(ev.duration, RCMM_PULSE_2, RCMM_UNIT / 2))
 119                         value = 2;
 120                 else if (eq_margin(ev.duration, RCMM_PULSE_3, RCMM_UNIT / 2))
 121                         value = 3;
 122                 else
 123                         value = -1;
 124 
 125                 if (value == -1) {
 126                         if (!rcmm_miscmode(dev, data))
 127                                 return 0;
 128                         break;
 129                 }
 130 
 131                 data->bits <<= 2;
 132                 data->bits |= value;
 133 
 134                 data->count += 2;
 135 
 136                 if (data->count < 32)
 137                         data->state = STATE_BUMP;
 138                 else
 139                         data->state = STATE_FINISHED;
 140 
 141                 return 0;
 142 
 143         case STATE_FINISHED:
 144                 if (!ev.pulse)
 145                         break;
 146 
 147                 if (!eq_margin(ev.duration, RCMM_UNIT, RCMM_UNIT / 2))
 148                         break;
 149 
 150                 if (rcmm_mode(data)) {
 151                         toggle = !!(0x8000 & data->bits);
 152                         scancode = data->bits & ~0x8000;
 153                 } else {
 154                         toggle = 0;
 155                         scancode = data->bits;
 156                 }
 157 
 158                 if (dev->enabled_protocols & RC_PROTO_BIT_RCMM32) {
 159                         rc_keydown(dev, RC_PROTO_RCMM32, scancode, toggle);
 160                         data->state = STATE_INACTIVE;
 161                         return 0;
 162                 }
 163 
 164                 break;
 165         }
 166 
 167         data->state = STATE_INACTIVE;
 168         return -EINVAL;
 169 }
 170 
 171 static const int rcmmspace[] = {
 172         RCMM_PULSE_0,
 173         RCMM_PULSE_1,
 174         RCMM_PULSE_2,
 175         RCMM_PULSE_3,
 176 };
 177 
 178 static int ir_rcmm_rawencoder(struct ir_raw_event **ev, unsigned int max,
 179                               unsigned int n, u32 data)
 180 {
 181         int i;
 182         int ret;
 183 
 184         ret = ir_raw_gen_pulse_space(ev, &max, RCMM_PREFIX_PULSE, RCMM_PULSE_0);
 185         if (ret)
 186                 return ret;
 187 
 188         for (i = n - 2; i >= 0; i -= 2) {
 189                 const unsigned int space = rcmmspace[(data >> i) & 3];
 190 
 191                 ret = ir_raw_gen_pulse_space(ev, &max, RCMM_UNIT, space);
 192                 if (ret)
 193                         return ret;
 194         }
 195 
 196         return ir_raw_gen_pulse_space(ev, &max, RCMM_UNIT, RCMM_PULSE_3 * 2);
 197 }
 198 
 199 static int ir_rcmm_encode(enum rc_proto protocol, u32 scancode,
 200                           struct ir_raw_event *events, unsigned int max)
 201 {
 202         struct ir_raw_event *e = events;
 203         int ret;
 204 
 205         switch (protocol) {
 206         case RC_PROTO_RCMM32:
 207                 ret = ir_rcmm_rawencoder(&e, max, 32, scancode);
 208                 break;
 209         case RC_PROTO_RCMM24:
 210                 ret = ir_rcmm_rawencoder(&e, max, 24, scancode);
 211                 break;
 212         case RC_PROTO_RCMM12:
 213                 ret = ir_rcmm_rawencoder(&e, max, 12, scancode);
 214                 break;
 215         default:
 216                 ret = -EINVAL;
 217         }
 218 
 219         if (ret < 0)
 220                 return ret;
 221 
 222         return e - events;
 223 }
 224 
 225 static struct ir_raw_handler rcmm_handler = {
 226         .protocols      = RC_PROTO_BIT_RCMM32 |
 227                           RC_PROTO_BIT_RCMM24 |
 228                           RC_PROTO_BIT_RCMM12,
 229         .decode         = ir_rcmm_decode,
 230         .encode         = ir_rcmm_encode,
 231         .carrier        = 36000,
 232         .min_timeout    = RCMM_PULSE_3 + RCMM_UNIT,
 233 };
 234 
 235 static int __init ir_rcmm_decode_init(void)
 236 {
 237         ir_raw_handler_register(&rcmm_handler);
 238 
 239         pr_info("IR RCMM protocol handler initialized\n");
 240         return 0;
 241 }
 242 
 243 static void __exit ir_rcmm_decode_exit(void)
 244 {
 245         ir_raw_handler_unregister(&rcmm_handler);
 246 }
 247 
 248 module_init(ir_rcmm_decode_init);
 249 module_exit(ir_rcmm_decode_exit);
 250 
 251 MODULE_LICENSE("GPL");
 252 MODULE_AUTHOR("Patrick Lerda");
 253 MODULE_DESCRIPTION("RCMM IR protocol decoder");

/* [<][>][^][v][top][bottom][index][help] */