| |
| |
| |
| |
| |
| #include "rc-core-priv.h" |
| #include <linux/module.h> |
| |
| #define RCMM_UNIT 166 |
| #define RCMM_PREFIX_PULSE 417 |
| #define RCMM_PULSE_0 278 |
| #define RCMM_PULSE_1 444 |
| #define RCMM_PULSE_2 611 |
| #define RCMM_PULSE_3 778 |
| |
| enum rcmm_state { |
| <------>STATE_INACTIVE, |
| <------>STATE_LOW, |
| <------>STATE_BUMP, |
| <------>STATE_VALUE, |
| <------>STATE_FINISHED, |
| }; |
| |
| static bool rcmm_mode(const struct rcmm_dec *data) |
| { |
| <------>return !((0x000c0000 & data->bits) == 0x000c0000); |
| } |
| |
| static int rcmm_miscmode(struct rc_dev *dev, struct rcmm_dec *data) |
| { |
| <------>switch (data->count) { |
| <------>case 24: |
| <------><------>if (dev->enabled_protocols & RC_PROTO_BIT_RCMM24) { |
| <------><------><------>rc_keydown(dev, RC_PROTO_RCMM24, data->bits, 0); |
| <------><------><------>data->state = STATE_INACTIVE; |
| <------><------><------>return 0; |
| <------><------>} |
| <------><------>return -1; |
| |
| <------>case 12: |
| <------><------>if (dev->enabled_protocols & RC_PROTO_BIT_RCMM12) { |
| <------><------><------>rc_keydown(dev, RC_PROTO_RCMM12, data->bits, 0); |
| <------><------><------>data->state = STATE_INACTIVE; |
| <------><------><------>return 0; |
| <------><------>} |
| <------><------>return -1; |
| <------>} |
| |
| <------>return -1; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| static int ir_rcmm_decode(struct rc_dev *dev, struct ir_raw_event ev) |
| { |
| <------>struct rcmm_dec *data = &dev->raw->rcmm; |
| <------>u32 scancode; |
| <------>u8 toggle; |
| <------>int value; |
| |
| <------>if (!(dev->enabled_protocols & (RC_PROTO_BIT_RCMM32 | |
| <------><------><------><------><------>RC_PROTO_BIT_RCMM24 | |
| <------><------><------><------><------>RC_PROTO_BIT_RCMM12))) |
| <------><------>return 0; |
| |
| <------>if (!is_timing_event(ev)) { |
| <------><------>if (ev.reset) |
| <------><------><------>data->state = STATE_INACTIVE; |
| <------><------>return 0; |
| <------>} |
| |
| <------>switch (data->state) { |
| <------>case STATE_INACTIVE: |
| <------><------>if (!ev.pulse) |
| <------><------><------>break; |
| |
| <------><------>if (!eq_margin(ev.duration, RCMM_PREFIX_PULSE, RCMM_UNIT)) |
| <------><------><------>break; |
| |
| <------><------>data->state = STATE_LOW; |
| <------><------>data->count = 0; |
| <------><------>data->bits = 0; |
| <------><------>return 0; |
| |
| <------>case STATE_LOW: |
| <------><------>if (ev.pulse) |
| <------><------><------>break; |
| |
| <------><------>if (!eq_margin(ev.duration, RCMM_PULSE_0, RCMM_UNIT)) |
| <------><------><------>break; |
| |
| <------><------>data->state = STATE_BUMP; |
| <------><------>return 0; |
| |
| <------>case STATE_BUMP: |
| <------><------>if (!ev.pulse) |
| <------><------><------>break; |
| |
| <------><------>if (!eq_margin(ev.duration, RCMM_UNIT, RCMM_UNIT / 2)) |
| <------><------><------>break; |
| |
| <------><------>data->state = STATE_VALUE; |
| <------><------>return 0; |
| |
| <------>case STATE_VALUE: |
| <------><------>if (ev.pulse) |
| <------><------><------>break; |
| |
| <------><------>if (eq_margin(ev.duration, RCMM_PULSE_0, RCMM_UNIT / 2)) |
| <------><------><------>value = 0; |
| <------><------>else if (eq_margin(ev.duration, RCMM_PULSE_1, RCMM_UNIT / 2)) |
| <------><------><------>value = 1; |
| <------><------>else if (eq_margin(ev.duration, RCMM_PULSE_2, RCMM_UNIT / 2)) |
| <------><------><------>value = 2; |
| <------><------>else if (eq_margin(ev.duration, RCMM_PULSE_3, RCMM_UNIT / 2)) |
| <------><------><------>value = 3; |
| <------><------>else |
| <------><------><------>value = -1; |
| |
| <------><------>if (value == -1) { |
| <------><------><------>if (!rcmm_miscmode(dev, data)) |
| <------><------><------><------>return 0; |
| <------><------><------>break; |
| <------><------>} |
| |
| <------><------>data->bits <<= 2; |
| <------><------>data->bits |= value; |
| |
| <------><------>data->count += 2; |
| |
| <------><------>if (data->count < 32) |
| <------><------><------>data->state = STATE_BUMP; |
| <------><------>else |
| <------><------><------>data->state = STATE_FINISHED; |
| |
| <------><------>return 0; |
| |
| <------>case STATE_FINISHED: |
| <------><------>if (!ev.pulse) |
| <------><------><------>break; |
| |
| <------><------>if (!eq_margin(ev.duration, RCMM_UNIT, RCMM_UNIT / 2)) |
| <------><------><------>break; |
| |
| <------><------>if (rcmm_mode(data)) { |
| <------><------><------>toggle = !!(0x8000 & data->bits); |
| <------><------><------>scancode = data->bits & ~0x8000; |
| <------><------>} else { |
| <------><------><------>toggle = 0; |
| <------><------><------>scancode = data->bits; |
| <------><------>} |
| |
| <------><------>if (dev->enabled_protocols & RC_PROTO_BIT_RCMM32) { |
| <------><------><------>rc_keydown(dev, RC_PROTO_RCMM32, scancode, toggle); |
| <------><------><------>data->state = STATE_INACTIVE; |
| <------><------><------>return 0; |
| <------><------>} |
| |
| <------><------>break; |
| <------>} |
| |
| <------>dev_dbg(&dev->dev, "RC-MM decode failed at count %d state %d (%uus %s)\n", |
| <------><------>data->count, data->state, ev.duration, TO_STR(ev.pulse)); |
| <------>data->state = STATE_INACTIVE; |
| <------>return -EINVAL; |
| } |
| |
| static const int rcmmspace[] = { |
| <------>RCMM_PULSE_0, |
| <------>RCMM_PULSE_1, |
| <------>RCMM_PULSE_2, |
| <------>RCMM_PULSE_3, |
| }; |
| |
| static int ir_rcmm_rawencoder(struct ir_raw_event **ev, unsigned int max, |
| <------><------><------> unsigned int n, u32 data) |
| { |
| <------>int i; |
| <------>int ret; |
| |
| <------>ret = ir_raw_gen_pulse_space(ev, &max, RCMM_PREFIX_PULSE, RCMM_PULSE_0); |
| <------>if (ret) |
| <------><------>return ret; |
| |
| <------>for (i = n - 2; i >= 0; i -= 2) { |
| <------><------>const unsigned int space = rcmmspace[(data >> i) & 3]; |
| |
| <------><------>ret = ir_raw_gen_pulse_space(ev, &max, RCMM_UNIT, space); |
| <------><------>if (ret) |
| <------><------><------>return ret; |
| <------>} |
| |
| <------>return ir_raw_gen_pulse_space(ev, &max, RCMM_UNIT, RCMM_PULSE_3 * 2); |
| } |
| |
| static int ir_rcmm_encode(enum rc_proto protocol, u32 scancode, |
| <------><------><------> struct ir_raw_event *events, unsigned int max) |
| { |
| <------>struct ir_raw_event *e = events; |
| <------>int ret; |
| |
| <------>switch (protocol) { |
| <------>case RC_PROTO_RCMM32: |
| <------><------>ret = ir_rcmm_rawencoder(&e, max, 32, scancode); |
| <------><------>break; |
| <------>case RC_PROTO_RCMM24: |
| <------><------>ret = ir_rcmm_rawencoder(&e, max, 24, scancode); |
| <------><------>break; |
| <------>case RC_PROTO_RCMM12: |
| <------><------>ret = ir_rcmm_rawencoder(&e, max, 12, scancode); |
| <------><------>break; |
| <------>default: |
| <------><------>ret = -EINVAL; |
| <------>} |
| |
| <------>if (ret < 0) |
| <------><------>return ret; |
| |
| <------>return e - events; |
| } |
| |
| static struct ir_raw_handler rcmm_handler = { |
| <------>.protocols = RC_PROTO_BIT_RCMM32 | |
| <------><------><------> RC_PROTO_BIT_RCMM24 | |
| <------><------><------> RC_PROTO_BIT_RCMM12, |
| <------>.decode = ir_rcmm_decode, |
| <------>.encode = ir_rcmm_encode, |
| <------>.carrier = 36000, |
| <------>.min_timeout = RCMM_PULSE_3 + RCMM_UNIT, |
| }; |
| |
| static int __init ir_rcmm_decode_init(void) |
| { |
| <------>ir_raw_handler_register(&rcmm_handler); |
| |
| <------>pr_info("IR RCMM protocol handler initialized\n"); |
| <------>return 0; |
| } |
| |
| static void __exit ir_rcmm_decode_exit(void) |
| { |
| <------>ir_raw_handler_unregister(&rcmm_handler); |
| } |
| |
| module_init(ir_rcmm_decode_init); |
| module_exit(ir_rcmm_decode_exit); |
| |
| MODULE_LICENSE("GPL"); |
| MODULE_AUTHOR("Patrick Lerda"); |
| MODULE_DESCRIPTION("RCMM IR protocol decoder"); |
| |