Mauro Carvalho Chehab | c3a3d1d | 2017-12-18 15:15:53 -0500 | [diff] [blame] | 1 | /* |
| 2 | * SPDX-License-Identifier: GPL-2.0 |
| 3 | * Remote Controller core raw events header |
| 4 | * |
| 5 | * Copyright (C) 2010 by Mauro Carvalho Chehab |
| 6 | */ |
Mauro Carvalho Chehab | 3f113e3 | 2010-04-08 15:10:27 -0300 | [diff] [blame] | 7 | |
David Härdeman | 829ba9f | 2010-11-19 20:43:27 -0300 | [diff] [blame] | 8 | #ifndef _RC_CORE_PRIV |
| 9 | #define _RC_CORE_PRIV |
Mauro Carvalho Chehab | 3f113e3 | 2010-04-08 15:10:27 -0300 | [diff] [blame] | 10 | |
Sean Young | a6ddd4f | 2017-09-26 09:34:47 -0400 | [diff] [blame] | 11 | #define RC_DEV_MAX 256 |
Heiner Kallweit | 464254e | 2015-11-27 20:02:38 -0200 | [diff] [blame] | 12 | /* Define the max number of pulse/space transitions to buffer */ |
| 13 | #define MAX_IR_EVENT_SIZE 512 |
| 14 | |
Mauro Carvalho Chehab | 3f113e3 | 2010-04-08 15:10:27 -0300 | [diff] [blame] | 15 | #include <linux/slab.h> |
Mauro Carvalho Chehab | 6bda964 | 2010-11-17 13:28:38 -0300 | [diff] [blame] | 16 | #include <media/rc-core.h> |
Mauro Carvalho Chehab | 3f113e3 | 2010-04-08 15:10:27 -0300 | [diff] [blame] | 17 | |
Sean Young | a60d64b | 2017-09-23 10:41:13 -0400 | [diff] [blame] | 18 | /** |
| 19 | * rc_open - Opens a RC device |
| 20 | * |
| 21 | * @rdev: pointer to struct rc_dev. |
| 22 | */ |
| 23 | int rc_open(struct rc_dev *rdev); |
| 24 | |
| 25 | /** |
| 26 | * rc_close - Closes a RC device |
| 27 | * |
| 28 | * @rdev: pointer to struct rc_dev. |
| 29 | */ |
| 30 | void rc_close(struct rc_dev *rdev); |
| 31 | |
Mauro Carvalho Chehab | 3f113e3 | 2010-04-08 15:10:27 -0300 | [diff] [blame] | 32 | struct ir_raw_handler { |
| 33 | struct list_head list; |
| 34 | |
David Härdeman | 667c9eb | 2010-06-13 17:29:31 -0300 | [diff] [blame] | 35 | u64 protocols; /* which are handled by this handler */ |
David Härdeman | d8b4b58 | 2010-10-29 16:08:23 -0300 | [diff] [blame] | 36 | int (*decode)(struct rc_dev *dev, struct ir_raw_event event); |
Sean Young | 6d741bf | 2017-08-07 16:20:58 -0400 | [diff] [blame] | 37 | int (*encode)(enum rc_proto protocol, u32 scancode, |
James Hogan | 3875233d | 2015-03-31 14:48:06 -0300 | [diff] [blame] | 38 | struct ir_raw_event *events, unsigned int max); |
Sean Young | cdfaa01 | 2017-02-25 06:51:30 -0500 | [diff] [blame] | 39 | u32 carrier; |
David Härdeman | c216369 | 2010-06-13 17:29:36 -0300 | [diff] [blame] | 40 | |
Sean Young | a60d64b | 2017-09-23 10:41:13 -0400 | [diff] [blame] | 41 | /* These two should only be used by the mce kbd decoder */ |
David Härdeman | d8b4b58 | 2010-10-29 16:08:23 -0300 | [diff] [blame] | 42 | int (*raw_register)(struct rc_dev *dev); |
| 43 | int (*raw_unregister)(struct rc_dev *dev); |
Mauro Carvalho Chehab | 3f113e3 | 2010-04-08 15:10:27 -0300 | [diff] [blame] | 44 | }; |
| 45 | |
| 46 | struct ir_raw_event_ctrl { |
David Härdeman | c216369 | 2010-06-13 17:29:36 -0300 | [diff] [blame] | 47 | struct list_head list; /* to keep track of raw clients */ |
Maxim Levitsky | 0d2cb1d | 2010-07-31 11:59:17 -0300 | [diff] [blame] | 48 | struct task_struct *thread; |
Heiner Kallweit | 464254e | 2015-11-27 20:02:38 -0200 | [diff] [blame] | 49 | /* fifo for the pulse/space durations */ |
| 50 | DECLARE_KFIFO(kfifo, struct ir_raw_event, MAX_IR_EVENT_SIZE); |
Mauro Carvalho Chehab | 3f113e3 | 2010-04-08 15:10:27 -0300 | [diff] [blame] | 51 | ktime_t last_event; /* when last event occurred */ |
David Härdeman | d8b4b58 | 2010-10-29 16:08:23 -0300 | [diff] [blame] | 52 | struct rc_dev *dev; /* pointer to the parent rc_dev */ |
Sean Young | e5e2643 | 2017-08-06 15:25:52 -0400 | [diff] [blame] | 53 | /* edge driver */ |
| 54 | struct timer_list edge_handle; |
David Härdeman | c216369 | 2010-06-13 17:29:36 -0300 | [diff] [blame] | 55 | |
| 56 | /* raw decoder state follows */ |
| 57 | struct ir_raw_event prev_ev; |
Maxim Levitsky | 4a702eb | 2010-07-31 11:59:22 -0300 | [diff] [blame] | 58 | struct ir_raw_event this_ev; |
David Härdeman | c216369 | 2010-06-13 17:29:36 -0300 | [diff] [blame] | 59 | struct nec_dec { |
| 60 | int state; |
| 61 | unsigned count; |
| 62 | u32 bits; |
Maxim Levitsky | 86ff071 | 2010-07-31 11:59:20 -0300 | [diff] [blame] | 63 | bool is_nec_x; |
| 64 | bool necx_repeat; |
David Härdeman | c216369 | 2010-06-13 17:29:36 -0300 | [diff] [blame] | 65 | } nec; |
| 66 | struct rc5_dec { |
| 67 | int state; |
| 68 | u32 bits; |
| 69 | unsigned count; |
David Härdeman | e87b540 | 2014-04-03 20:32:31 -0300 | [diff] [blame] | 70 | bool is_rc5x; |
David Härdeman | c216369 | 2010-06-13 17:29:36 -0300 | [diff] [blame] | 71 | } rc5; |
| 72 | struct rc6_dec { |
| 73 | int state; |
| 74 | u8 header; |
| 75 | u32 body; |
| 76 | bool toggle; |
| 77 | unsigned count; |
| 78 | unsigned wanted_bits; |
| 79 | } rc6; |
| 80 | struct sony_dec { |
| 81 | int state; |
| 82 | u32 bits; |
| 83 | unsigned count; |
| 84 | } sony; |
| 85 | struct jvc_dec { |
| 86 | int state; |
| 87 | u16 bits; |
| 88 | u16 old_bits; |
| 89 | unsigned count; |
| 90 | bool first; |
| 91 | bool toggle; |
| 92 | } jvc; |
Mauro Carvalho Chehab | b32e724 | 2011-11-23 12:04:08 -0300 | [diff] [blame] | 93 | struct sanyo_dec { |
| 94 | int state; |
| 95 | unsigned count; |
| 96 | u64 bits; |
| 97 | } sanyo; |
James Hogan | 1d184b0 | 2014-01-17 10:58:48 -0300 | [diff] [blame] | 98 | struct sharp_dec { |
| 99 | int state; |
| 100 | unsigned count; |
| 101 | u32 bits; |
| 102 | unsigned int pulse_len; |
| 103 | } sharp; |
Jarod Wilson | f5f2cc6 | 2011-07-13 18:09:48 -0300 | [diff] [blame] | 104 | struct mce_kbd_dec { |
| 105 | struct input_dev *idev; |
| 106 | struct timer_list rx_timeout; |
| 107 | char name[64]; |
| 108 | char phys[64]; |
| 109 | int state; |
| 110 | u8 header; |
| 111 | u32 body; |
| 112 | unsigned count; |
| 113 | unsigned wanted_bits; |
| 114 | } mce_kbd; |
Marcel J.E. Mol | 1dee9b5 | 2014-07-26 17:28:26 -0300 | [diff] [blame] | 115 | struct xmp_dec { |
| 116 | int state; |
| 117 | unsigned count; |
| 118 | u32 durations[16]; |
| 119 | } xmp; |
Mauro Carvalho Chehab | 3f113e3 | 2010-04-08 15:10:27 -0300 | [diff] [blame] | 120 | }; |
| 121 | |
| 122 | /* macros for IR decoders */ |
Mauro Carvalho Chehab | 384f23e | 2010-04-20 18:50:54 -0300 | [diff] [blame] | 123 | static inline bool geq_margin(unsigned d1, unsigned d2, unsigned margin) |
| 124 | { |
David Härdeman | e40b112 | 2010-04-15 18:46:00 -0300 | [diff] [blame] | 125 | return d1 > (d2 - margin); |
| 126 | } |
Mauro Carvalho Chehab | 3f113e3 | 2010-04-08 15:10:27 -0300 | [diff] [blame] | 127 | |
Mauro Carvalho Chehab | 384f23e | 2010-04-20 18:50:54 -0300 | [diff] [blame] | 128 | static inline bool eq_margin(unsigned d1, unsigned d2, unsigned margin) |
| 129 | { |
David Härdeman | e40b112 | 2010-04-15 18:46:00 -0300 | [diff] [blame] | 130 | return ((d1 > (d2 - margin)) && (d1 < (d2 + margin))); |
| 131 | } |
| 132 | |
Mauro Carvalho Chehab | 384f23e | 2010-04-20 18:50:54 -0300 | [diff] [blame] | 133 | static inline bool is_transition(struct ir_raw_event *x, struct ir_raw_event *y) |
| 134 | { |
David Härdeman | e40b112 | 2010-04-15 18:46:00 -0300 | [diff] [blame] | 135 | return x->pulse != y->pulse; |
| 136 | } |
| 137 | |
Mauro Carvalho Chehab | 384f23e | 2010-04-20 18:50:54 -0300 | [diff] [blame] | 138 | static inline void decrease_duration(struct ir_raw_event *ev, unsigned duration) |
| 139 | { |
David Härdeman | e40b112 | 2010-04-15 18:46:00 -0300 | [diff] [blame] | 140 | if (duration > ev->duration) |
| 141 | ev->duration = 0; |
| 142 | else |
| 143 | ev->duration -= duration; |
| 144 | } |
| 145 | |
Maxim Levitsky | 4651918 | 2010-10-16 19:56:28 -0300 | [diff] [blame] | 146 | /* Returns true if event is normal pulse/space event */ |
| 147 | static inline bool is_timing_event(struct ir_raw_event ev) |
| 148 | { |
| 149 | return !ev.carrier_report && !ev.reset; |
| 150 | } |
| 151 | |
Maxim Levitsky | 510fcb7 | 2010-07-31 11:59:15 -0300 | [diff] [blame] | 152 | #define TO_US(duration) DIV_ROUND_CLOSEST((duration), 1000) |
David Härdeman | e40b112 | 2010-04-15 18:46:00 -0300 | [diff] [blame] | 153 | #define TO_STR(is_pulse) ((is_pulse) ? "pulse" : "space") |
Mauro Carvalho Chehab | 3f113e3 | 2010-04-08 15:10:27 -0300 | [diff] [blame] | 154 | |
Antti Seppälä | 844a4f4 | 2015-03-31 14:48:07 -0300 | [diff] [blame] | 155 | /* functions for IR encoders */ |
Sean Young | 49a4b36 | 2017-09-27 16:00:49 -0400 | [diff] [blame] | 156 | bool rc_validate_scancode(enum rc_proto proto, u32 scancode); |
Antti Seppälä | 844a4f4 | 2015-03-31 14:48:07 -0300 | [diff] [blame] | 157 | |
| 158 | static inline void init_ir_raw_event_duration(struct ir_raw_event *ev, |
| 159 | unsigned int pulse, |
| 160 | u32 duration) |
| 161 | { |
| 162 | init_ir_raw_event(ev); |
| 163 | ev->duration = duration; |
| 164 | ev->pulse = pulse; |
| 165 | } |
| 166 | |
| 167 | /** |
| 168 | * struct ir_raw_timings_manchester - Manchester coding timings |
| 169 | * @leader: duration of leader pulse (if any) 0 if continuing |
| 170 | * existing signal (see @pulse_space_start) |
| 171 | * @pulse_space_start: 1 for starting with pulse (0 for starting with space) |
| 172 | * @clock: duration of each pulse/space in ns |
| 173 | * @invert: if set clock logic is inverted |
| 174 | * (0 = space + pulse, 1 = pulse + space) |
| 175 | * @trailer_space: duration of trailer space in ns |
| 176 | */ |
| 177 | struct ir_raw_timings_manchester { |
| 178 | unsigned int leader; |
| 179 | unsigned int pulse_space_start:1; |
| 180 | unsigned int clock; |
| 181 | unsigned int invert:1; |
| 182 | unsigned int trailer_space; |
| 183 | }; |
| 184 | |
| 185 | int ir_raw_gen_manchester(struct ir_raw_event **ev, unsigned int max, |
| 186 | const struct ir_raw_timings_manchester *timings, |
Sean Young | b73bc16 | 2017-02-11 20:33:38 -0200 | [diff] [blame] | 187 | unsigned int n, u64 data); |
Antti Seppälä | 844a4f4 | 2015-03-31 14:48:07 -0300 | [diff] [blame] | 188 | |
James Hogan | caec098 | 2014-03-14 20:04:12 -0300 | [diff] [blame] | 189 | /** |
| 190 | * ir_raw_gen_pulse_space() - generate pulse and space raw events. |
| 191 | * @ev: Pointer to pointer to next free raw event. |
| 192 | * Will be incremented for each raw event written. |
| 193 | * @max: Pointer to number of raw events available in buffer. |
| 194 | * Will be decremented for each raw event written. |
| 195 | * @pulse_width: Width of pulse in ns. |
| 196 | * @space_width: Width of space in ns. |
| 197 | * |
| 198 | * Returns: 0 on success. |
| 199 | * -ENOBUFS if there isn't enough buffer space to write both raw |
| 200 | * events. In this case @max events will have been written. |
| 201 | */ |
| 202 | static inline int ir_raw_gen_pulse_space(struct ir_raw_event **ev, |
| 203 | unsigned int *max, |
| 204 | unsigned int pulse_width, |
| 205 | unsigned int space_width) |
| 206 | { |
| 207 | if (!*max) |
| 208 | return -ENOBUFS; |
| 209 | init_ir_raw_event_duration((*ev)++, 1, pulse_width); |
| 210 | if (!--*max) |
| 211 | return -ENOBUFS; |
| 212 | init_ir_raw_event_duration((*ev)++, 0, space_width); |
| 213 | --*max; |
| 214 | return 0; |
| 215 | } |
| 216 | |
| 217 | /** |
| 218 | * struct ir_raw_timings_pd - pulse-distance modulation timings |
| 219 | * @header_pulse: duration of header pulse in ns (0 for none) |
| 220 | * @header_space: duration of header space in ns |
| 221 | * @bit_pulse: duration of bit pulse in ns |
| 222 | * @bit_space: duration of bit space (for logic 0 and 1) in ns |
| 223 | * @trailer_pulse: duration of trailer pulse in ns |
| 224 | * @trailer_space: duration of trailer space in ns |
| 225 | * @msb_first: 1 if most significant bit is sent first |
| 226 | */ |
| 227 | struct ir_raw_timings_pd { |
| 228 | unsigned int header_pulse; |
| 229 | unsigned int header_space; |
| 230 | unsigned int bit_pulse; |
| 231 | unsigned int bit_space[2]; |
| 232 | unsigned int trailer_pulse; |
| 233 | unsigned int trailer_space; |
| 234 | unsigned int msb_first:1; |
| 235 | }; |
| 236 | |
| 237 | int ir_raw_gen_pd(struct ir_raw_event **ev, unsigned int max, |
| 238 | const struct ir_raw_timings_pd *timings, |
| 239 | unsigned int n, u64 data); |
| 240 | |
Sean Young | 103293b | 2016-12-06 18:33:57 -0200 | [diff] [blame] | 241 | /** |
| 242 | * struct ir_raw_timings_pl - pulse-length modulation timings |
| 243 | * @header_pulse: duration of header pulse in ns (0 for none) |
| 244 | * @bit_space: duration of bit space in ns |
| 245 | * @bit_pulse: duration of bit pulse (for logic 0 and 1) in ns |
| 246 | * @trailer_space: duration of trailer space in ns |
| 247 | * @msb_first: 1 if most significant bit is sent first |
| 248 | */ |
| 249 | struct ir_raw_timings_pl { |
| 250 | unsigned int header_pulse; |
| 251 | unsigned int bit_space; |
| 252 | unsigned int bit_pulse[2]; |
| 253 | unsigned int trailer_space; |
| 254 | unsigned int msb_first:1; |
| 255 | }; |
| 256 | |
| 257 | int ir_raw_gen_pl(struct ir_raw_event **ev, unsigned int max, |
| 258 | const struct ir_raw_timings_pl *timings, |
| 259 | unsigned int n, u64 data); |
| 260 | |
Mauro Carvalho Chehab | 3f113e3 | 2010-04-08 15:10:27 -0300 | [diff] [blame] | 261 | /* |
David Härdeman | d8b4b58 | 2010-10-29 16:08:23 -0300 | [diff] [blame] | 262 | * Routines from rc-raw.c to be used internally and by decoders |
Mauro Carvalho Chehab | 3f113e3 | 2010-04-08 15:10:27 -0300 | [diff] [blame] | 263 | */ |
David Härdeman | 667c9eb | 2010-06-13 17:29:31 -0300 | [diff] [blame] | 264 | u64 ir_raw_get_allowed_protocols(void); |
David Härdeman | f56928a | 2017-05-03 07:04:00 -0300 | [diff] [blame] | 265 | int ir_raw_event_prepare(struct rc_dev *dev); |
David Härdeman | d8b4b58 | 2010-10-29 16:08:23 -0300 | [diff] [blame] | 266 | int ir_raw_event_register(struct rc_dev *dev); |
David Härdeman | f56928a | 2017-05-03 07:04:00 -0300 | [diff] [blame] | 267 | void ir_raw_event_free(struct rc_dev *dev); |
David Härdeman | d8b4b58 | 2010-10-29 16:08:23 -0300 | [diff] [blame] | 268 | void ir_raw_event_unregister(struct rc_dev *dev); |
Mauro Carvalho Chehab | 3f113e3 | 2010-04-08 15:10:27 -0300 | [diff] [blame] | 269 | int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler); |
| 270 | void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler); |
Sean Young | 0d39ab0 | 2017-02-25 06:51:31 -0500 | [diff] [blame] | 271 | void ir_raw_load_modules(u64 *protocols); |
Mauro Carvalho Chehab | 3f113e3 | 2010-04-08 15:10:27 -0300 | [diff] [blame] | 272 | void ir_raw_init(void); |
| 273 | |
Mauro Carvalho Chehab | 3f113e3 | 2010-04-08 15:10:27 -0300 | [diff] [blame] | 274 | /* |
Sean Young | a60d64b | 2017-09-23 10:41:13 -0400 | [diff] [blame] | 275 | * lirc interface |
| 276 | */ |
| 277 | #ifdef CONFIG_LIRC |
| 278 | int lirc_dev_init(void); |
| 279 | void lirc_dev_exit(void); |
| 280 | void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev); |
Sean Young | de142c3 | 2017-02-25 06:51:32 -0500 | [diff] [blame] | 281 | void ir_lirc_scancode_event(struct rc_dev *dev, struct lirc_scancode *lsc); |
Sean Young | a60d64b | 2017-09-23 10:41:13 -0400 | [diff] [blame] | 282 | int ir_lirc_register(struct rc_dev *dev); |
| 283 | void ir_lirc_unregister(struct rc_dev *dev); |
| 284 | #else |
| 285 | static inline int lirc_dev_init(void) { return 0; } |
| 286 | static inline void lirc_dev_exit(void) {} |
| 287 | static inline void ir_lirc_raw_event(struct rc_dev *dev, |
| 288 | struct ir_raw_event ev) { } |
Sean Young | de142c3 | 2017-02-25 06:51:32 -0500 | [diff] [blame] | 289 | static inline void ir_lirc_scancode_event(struct rc_dev *dev, |
| 290 | struct lirc_scancode *lsc) { } |
Sean Young | a60d64b | 2017-09-23 10:41:13 -0400 | [diff] [blame] | 291 | static inline int ir_lirc_register(struct rc_dev *dev) { return 0; } |
| 292 | static inline void ir_lirc_unregister(struct rc_dev *dev) { } |
| 293 | #endif |
| 294 | |
| 295 | /* |
Mauro Carvalho Chehab | 3f113e3 | 2010-04-08 15:10:27 -0300 | [diff] [blame] | 296 | * Decoder initialization code |
| 297 | * |
| 298 | * Those load logic are called during ir-core init, and automatically |
| 299 | * loads the compiled decoders for their usage with IR raw events |
| 300 | */ |
| 301 | |
David Härdeman | 829ba9f | 2010-11-19 20:43:27 -0300 | [diff] [blame] | 302 | #endif /* _RC_CORE_PRIV */ |