diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-04 09:50:07 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-04 09:50:07 -0700 |
| commit | 3c83e61e67256e0bb08c46cc2db43b58fd617251 (patch) | |
| tree | 0233e1e04e6449c60b01ff5dea8bea85bcf22f08 /drivers/media/rc/ir-sharp-decoder.c | |
| parent | 4a4389abdd9822fdf3cc2ac6ed87eb811fd43acc (diff) | |
| parent | a83b93a7480441a47856dc9104bea970e84cda87 (diff) | |
Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
"The main set of series of patches for media subsystem, including:
- document RC sysfs class
- added an API to setup scancode to allow waking up systems using the
Remote Controller
- add API for SDR devices. Drivers are still on staging
- some API improvements for getting EDID data from media
inputs/outputs
- new DVB frontend driver for drx-j (ATSC)
- one driver (it913x/it9137) got removed, in favor of an improvement
on another driver (af9035)
- added a skeleton V4L2 PCI driver at documentation
- added a dual flash driver (lm3646)
- added a new IR driver (img-ir)
- added an IR scancode decoder for the Sharp protocol
- some improvements at the usbtv driver, to allow its core to be
reused.
- added a new SDR driver (rtl2832u_sdr)
- added a new tuner driver (msi001)
- several improvements at em28xx driver to fix PM support, device
removal and to split the V4L2 specific bits into a separate
sub-driver
- one driver got converted to videobuf2 (s2255drv)
- the e4000 tuner driver now follows an improved binding model
- some fixes at V4L2 compat32 code
- several fixes and enhancements at videobuf2 code
- some cleanups at V4L2 API documentation
- usual driver enhancements, new board additions and misc fixups"
[ NOTE! This merge effective drops commit 4329b93b283c ("of: Reduce
indentation in of_graph_get_next_endpoint").
The of_graph_get_next_endpoint() function was moved and renamed by
commit fd9fdb78a9bf ("[media] of: move graph helpers from
drivers/media/v4l2-core to drivers/of"). It was originally called
v4l2_of_get_next_endpoint() and lived in the file
drivers/media/v4l2-core/v4l2-of.c.
In that original location, it was then fixed to support empty port
nodes by commit b9db140c1e46 ("[media] v4l: of: Support empty port
nodes"), and that commit clashes badly with the dropped "Reduce
intendation" commit. I had to choose one or the other, and decided
that the "Support empty port nodes" commit was more important ]
* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (426 commits)
[media] em28xx-dvb: fix PCTV 461e tuner I2C binding
Revert "[media] em28xx-dvb: fix PCTV 461e tuner I2C binding"
[media] em28xx: fix PCTV 290e LNA oops
[media] em28xx-dvb: fix PCTV 461e tuner I2C binding
[media] m88ds3103: fix bug on .set_tone()
[media] saa7134: fix WARN_ON during resume
[media] v4l2-dv-timings: add module name, description, license
[media] videodev2.h: add parenthesis around macro arguments
[media] saa6752hs: depends on CRC32
[media] si4713: fix Kconfig dependencies
[media] Sensoray 2255 uses videobuf2
[media] adv7180: free an interrupt on failure paths in init_device()
[media] e4000: make VIDEO_V4L2 dependency optional
[media] af9033: Don't export functions for the hardware filter
[media] af9035: use af9033 PID filters
[media] af9033: implement PID filter
[media] rtl2832_sdr: do not use dynamic stack allocation
[media] e4000: fix 32-bit build error
[media] em28xx-audio: make sure audio is unmuted on open()
[media] DocBook media: v4l2_format_sdr was renamed to v4l2_sdr_format
...
Diffstat (limited to 'drivers/media/rc/ir-sharp-decoder.c')
| -rw-r--r-- | drivers/media/rc/ir-sharp-decoder.c | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/drivers/media/rc/ir-sharp-decoder.c b/drivers/media/rc/ir-sharp-decoder.c new file mode 100644 index 000000000000..66d20394ceaa --- /dev/null +++ b/drivers/media/rc/ir-sharp-decoder.c @@ -0,0 +1,200 @@ +/* ir-sharp-decoder.c - handle Sharp IR Pulse/Space protocol + * + * Copyright (C) 2013-2014 Imagination Technologies Ltd. + * + * Based on NEC decoder: + * Copyright (C) 2010 by Mauro Carvalho Chehab + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/bitrev.h> +#include <linux/module.h> +#include "rc-core-priv.h" + +#define SHARP_NBITS 15 +#define SHARP_UNIT 40000 /* ns */ +#define SHARP_BIT_PULSE (8 * SHARP_UNIT) /* 320us */ +#define SHARP_BIT_0_PERIOD (25 * SHARP_UNIT) /* 1ms (680us space) */ +#define SHARP_BIT_1_PERIOD (50 * SHARP_UNIT) /* 2ms (1680ms space) */ +#define SHARP_ECHO_SPACE (1000 * SHARP_UNIT) /* 40 ms */ +#define SHARP_TRAILER_SPACE (125 * SHARP_UNIT) /* 5 ms (even longer) */ + +enum sharp_state { + STATE_INACTIVE, + STATE_BIT_PULSE, + STATE_BIT_SPACE, + STATE_TRAILER_PULSE, + STATE_ECHO_SPACE, + STATE_TRAILER_SPACE, +}; + +/** + * ir_sharp_decode() - Decode one Sharp pulse or space + * @dev: the struct rc_dev descriptor of the device + * @duration: the struct ir_raw_event descriptor of the pulse/space + * + * This function returns -EINVAL if the pulse violates the state machine + */ +static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev) +{ + struct sharp_dec *data = &dev->raw->sharp; + u32 msg, echo, address, command, scancode; + + if (!rc_protocols_enabled(dev, RC_BIT_SHARP)) + return 0; + + if (!is_timing_event(ev)) { + if (ev.reset) + data->state = STATE_INACTIVE; + return 0; + } + + IR_dprintk(2, "Sharp decode started at state %d (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + + switch (data->state) { + + case STATE_INACTIVE: + if (!ev.pulse) + break; + + if (!eq_margin(ev.duration, SHARP_BIT_PULSE, + SHARP_BIT_PULSE / 2)) + break; + + data->count = 0; + data->pulse_len = ev.duration; + data->state = STATE_BIT_SPACE; + return 0; + + case STATE_BIT_PULSE: + if (!ev.pulse) + break; + + if (!eq_margin(ev.duration, SHARP_BIT_PULSE, + SHARP_BIT_PULSE / 2)) + break; + + data->pulse_len = ev.duration; + data->state = STATE_BIT_SPACE; + return 0; + + case STATE_BIT_SPACE: + if (ev.pulse) + break; + + data->bits <<= 1; + if (eq_margin(data->pulse_len + ev.duration, SHARP_BIT_1_PERIOD, + SHARP_BIT_PULSE * 2)) + data->bits |= 1; + else if (!eq_margin(data->pulse_len + ev.duration, + SHARP_BIT_0_PERIOD, SHARP_BIT_PULSE * 2)) + break; + data->count++; + + if (data->count == SHARP_NBITS || + data->count == SHARP_NBITS * 2) + data->state = STATE_TRAILER_PULSE; + else + data->state = STATE_BIT_PULSE; + + return 0; + + case STATE_TRAILER_PULSE: + if (!ev.pulse) + break; + + if (!eq_margin(ev.duration, SHARP_BIT_PULSE, + SHARP_BIT_PULSE / 2)) + break; + + if (data->count == SHARP_NBITS) { + /* exp,chk bits should be 1,0 */ + if ((data->bits & 0x3) != 0x2) + break; + data->state = STATE_ECHO_SPACE; + } else { + data->state = STATE_TRAILER_SPACE; + } + return 0; + + case STATE_ECHO_SPACE: + if (ev.pulse) + break; + + if (!eq_margin(ev.duration, SHARP_ECHO_SPACE, + SHARP_ECHO_SPACE / 4)) + break; + + data->state = STATE_BIT_PULSE; + + return 0; + + case STATE_TRAILER_SPACE: + if (ev.pulse) + break; + + if (!geq_margin(ev.duration, SHARP_TRAILER_SPACE, + SHARP_BIT_PULSE / 2)) + break; + + /* Validate - command, ext, chk should be inverted in 2nd */ + msg = (data->bits >> 15) & 0x7fff; + echo = data->bits & 0x7fff; + if ((msg ^ echo) != 0x3ff) { + IR_dprintk(1, + "Sharp checksum error: received 0x%04x, 0x%04x\n", + msg, echo); + break; + } + + address = bitrev8((msg >> 7) & 0xf8); + command = bitrev8((msg >> 2) & 0xff); + + scancode = address << 8 | command; + IR_dprintk(1, "Sharp scancode 0x%04x\n", scancode); + + rc_keydown(dev, scancode, 0); + data->state = STATE_INACTIVE; + return 0; + } + + IR_dprintk(1, "Sharp decode failed at count %d state %d (%uus %s)\n", + data->count, data->state, TO_US(ev.duration), + TO_STR(ev.pulse)); + data->state = STATE_INACTIVE; + return -EINVAL; +} + +static struct ir_raw_handler sharp_handler = { + .protocols = RC_BIT_SHARP, + .decode = ir_sharp_decode, +}; + +static int __init ir_sharp_decode_init(void) +{ + ir_raw_handler_register(&sharp_handler); + + pr_info("IR Sharp protocol handler initialized\n"); + return 0; +} + +static void __exit ir_sharp_decode_exit(void) +{ + ir_raw_handler_unregister(&sharp_handler); +} + +module_init(ir_sharp_decode_init); +module_exit(ir_sharp_decode_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("James Hogan <james.hogan@imgtec.com>"); +MODULE_DESCRIPTION("Sharp IR protocol decoder"); |
