diff options
Diffstat (limited to 'drivers/media/video/cx23885/cx23885-input.c')
-rw-r--r-- | drivers/media/video/cx23885/cx23885-input.c | 317 |
1 files changed, 109 insertions, 208 deletions
diff --git a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c index 5de6ba98f7a8..d0b1613ede2f 100644 --- a/drivers/media/video/cx23885/cx23885-input.c +++ b/drivers/media/video/cx23885/cx23885-input.c | |||
@@ -37,161 +37,55 @@ | |||
37 | 37 | ||
38 | #include <linux/input.h> | 38 | #include <linux/input.h> |
39 | #include <linux/slab.h> | 39 | #include <linux/slab.h> |
40 | #include <media/ir-common.h> | 40 | #include <media/ir-core.h> |
41 | #include <media/v4l2-subdev.h> | 41 | #include <media/v4l2-subdev.h> |
42 | 42 | ||
43 | #include "cx23885.h" | 43 | #include "cx23885.h" |
44 | 44 | ||
45 | #define RC5_BITS 14 | ||
46 | #define RC5_HALF_BITS (2*RC5_BITS) | ||
47 | #define RC5_HALF_BITS_MASK ((1 << RC5_HALF_BITS) - 1) | ||
48 | |||
49 | #define RC5_START_BITS_NORMAL 0x3 /* Command range 0 - 63 */ | ||
50 | #define RC5_START_BITS_EXTENDED 0x2 /* Command range 64 - 127 */ | ||
51 | |||
52 | #define RC5_EXTENDED_COMMAND_OFFSET 64 | ||
53 | |||
54 | #define MODULE_NAME "cx23885" | 45 | #define MODULE_NAME "cx23885" |
55 | 46 | ||
56 | static inline unsigned int rc5_command(u32 rc5_baseband) | 47 | static void convert_measurement(u32 x, struct ir_raw_event *y) |
57 | { | 48 | { |
58 | return RC5_INSTR(rc5_baseband) + | 49 | if (x == V4L2_SUBDEV_IR_PULSE_RX_SEQ_END) { |
59 | ((RC5_START(rc5_baseband) == RC5_START_BITS_EXTENDED) | 50 | y->pulse = false; |
60 | ? RC5_EXTENDED_COMMAND_OFFSET : 0); | 51 | y->duration = V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS; |
61 | } | ||
62 | |||
63 | static void cx23885_input_process_raw_rc5(struct cx23885_dev *dev) | ||
64 | { | ||
65 | struct card_ir *ir_input = dev->ir_input; | ||
66 | unsigned int code, command; | ||
67 | u32 rc5; | ||
68 | |||
69 | /* Ignore codes that are too short to be valid RC-5 */ | ||
70 | if (ir_input->last_bit < (RC5_HALF_BITS - 1)) | ||
71 | return; | ||
72 | |||
73 | /* The library has the manchester coding backwards; XOR to adapt. */ | ||
74 | code = (ir_input->code & RC5_HALF_BITS_MASK) ^ RC5_HALF_BITS_MASK; | ||
75 | rc5 = ir_rc5_decode(code); | ||
76 | |||
77 | switch (RC5_START(rc5)) { | ||
78 | case RC5_START_BITS_NORMAL: | ||
79 | break; | ||
80 | case RC5_START_BITS_EXTENDED: | ||
81 | /* Don't allow if the remote only emits standard commands */ | ||
82 | if (ir_input->start == RC5_START_BITS_NORMAL) | ||
83 | return; | ||
84 | break; | ||
85 | default: | ||
86 | return; | 52 | return; |
87 | } | 53 | } |
88 | 54 | ||
89 | if (ir_input->addr != RC5_ADDR(rc5)) | 55 | y->pulse = (x & V4L2_SUBDEV_IR_PULSE_LEVEL_MASK) ? true : false; |
90 | return; | 56 | y->duration = x & V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS; |
91 | |||
92 | /* Don't generate a keypress for RC-5 auto-repeated keypresses */ | ||
93 | command = rc5_command(rc5); | ||
94 | if (RC5_TOGGLE(rc5) != RC5_TOGGLE(ir_input->last_rc5) || | ||
95 | command != rc5_command(ir_input->last_rc5) || | ||
96 | /* Catch T == 0, CMD == 0 (e.g. '0') as first keypress after init */ | ||
97 | RC5_START(ir_input->last_rc5) == 0) { | ||
98 | /* This keypress is differnet: not an auto repeat */ | ||
99 | ir_input_nokey(ir_input->dev, &ir_input->ir); | ||
100 | ir_input_keydown(ir_input->dev, &ir_input->ir, command); | ||
101 | } | ||
102 | ir_input->last_rc5 = rc5; | ||
103 | |||
104 | /* Schedule when we should do the key up event: ir_input_nokey() */ | ||
105 | mod_timer(&ir_input->timer_keyup, | ||
106 | jiffies + msecs_to_jiffies(ir_input->rc5_key_timeout)); | ||
107 | } | 57 | } |
108 | 58 | ||
109 | static void cx23885_input_next_pulse_width_rc5(struct cx23885_dev *dev, | 59 | static void cx23885_input_process_measurements(struct cx23885_dev *dev, |
110 | u32 ns_pulse) | 60 | bool overrun) |
111 | { | 61 | { |
112 | const int rc5_quarterbit_ns = 444444; /* 32 cycles/36 kHz/2 = 444 us */ | 62 | struct cx23885_kernel_ir *kernel_ir = dev->kernel_ir; |
113 | struct card_ir *ir_input = dev->ir_input; | 63 | struct ir_raw_event kernel_ir_event; |
114 | int i, level, quarterbits, halfbits; | ||
115 | |||
116 | if (!ir_input->active) { | ||
117 | ir_input->active = 1; | ||
118 | /* assume an initial space that we may not detect or measure */ | ||
119 | ir_input->code = 0; | ||
120 | ir_input->last_bit = 0; | ||
121 | } | ||
122 | 64 | ||
123 | if (ns_pulse == V4L2_SUBDEV_IR_PULSE_RX_SEQ_END) { | 65 | u32 sd_ir_data[64]; |
124 | ir_input->last_bit++; /* Account for the final space */ | 66 | ssize_t num; |
125 | ir_input->active = 0; | ||
126 | cx23885_input_process_raw_rc5(dev); | ||
127 | return; | ||
128 | } | ||
129 | |||
130 | level = (ns_pulse & V4L2_SUBDEV_IR_PULSE_LEVEL_MASK) ? 1 : 0; | ||
131 | |||
132 | /* Skip any leading space to sync to the start bit */ | ||
133 | if (ir_input->last_bit == 0 && level == 0) | ||
134 | return; | ||
135 | |||
136 | /* | ||
137 | * With valid RC-5 we can get up to two consecutive half-bits in a | ||
138 | * single pulse measurment. Experiments have shown that the duration | ||
139 | * of a half-bit can vary. Make sure we always end up with an even | ||
140 | * number of quarter bits at the same level (mark or space). | ||
141 | */ | ||
142 | ns_pulse &= V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS; | ||
143 | quarterbits = ns_pulse / rc5_quarterbit_ns; | ||
144 | if (quarterbits & 1) | ||
145 | quarterbits++; | ||
146 | halfbits = quarterbits / 2; | ||
147 | |||
148 | for (i = 0; i < halfbits; i++) { | ||
149 | ir_input->last_bit++; | ||
150 | ir_input->code |= (level << ir_input->last_bit); | ||
151 | |||
152 | if (ir_input->last_bit >= RC5_HALF_BITS-1) { | ||
153 | ir_input->active = 0; | ||
154 | cx23885_input_process_raw_rc5(dev); | ||
155 | /* | ||
156 | * If level is 1, a leading mark is invalid for RC5. | ||
157 | * If level is 0, we scan past extra intial space. | ||
158 | * Either way we don't want to reactivate collecting | ||
159 | * marks or spaces here with any left over half-bits. | ||
160 | */ | ||
161 | break; | ||
162 | } | ||
163 | } | ||
164 | } | ||
165 | |||
166 | static void cx23885_input_process_pulse_widths_rc5(struct cx23885_dev *dev, | ||
167 | bool add_eom) | ||
168 | { | ||
169 | struct card_ir *ir_input = dev->ir_input; | ||
170 | struct ir_input_state *ir_input_state = &ir_input->ir; | ||
171 | |||
172 | u32 ns_pulse[RC5_HALF_BITS+1]; | ||
173 | ssize_t num = 0; | ||
174 | int count, i; | 67 | int count, i; |
68 | bool handle = false; | ||
175 | 69 | ||
176 | do { | 70 | do { |
177 | v4l2_subdev_call(dev->sd_ir, ir, rx_read, (u8 *) ns_pulse, | 71 | num = 0; |
178 | sizeof(ns_pulse), &num); | 72 | v4l2_subdev_call(dev->sd_ir, ir, rx_read, (u8 *) sd_ir_data, |
73 | sizeof(sd_ir_data), &num); | ||
179 | 74 | ||
180 | count = num / sizeof(u32); | 75 | count = num / sizeof(u32); |
181 | 76 | ||
182 | /* Append an end of Rx seq, if the caller requested */ | 77 | for (i = 0; i < count; i++) { |
183 | if (add_eom && count < ARRAY_SIZE(ns_pulse)) { | 78 | convert_measurement(sd_ir_data[i], &kernel_ir_event); |
184 | ns_pulse[count] = V4L2_SUBDEV_IR_PULSE_RX_SEQ_END; | 79 | ir_raw_event_store(kernel_ir->inp_dev, |
185 | count++; | 80 | &kernel_ir_event); |
81 | handle = true; | ||
186 | } | 82 | } |
187 | |||
188 | /* Just drain the Rx FIFO, if we're called, but not RC-5 */ | ||
189 | if (ir_input_state->ir_type != IR_TYPE_RC5) | ||
190 | continue; | ||
191 | |||
192 | for (i = 0; i < count; i++) | ||
193 | cx23885_input_next_pulse_width_rc5(dev, ns_pulse[i]); | ||
194 | } while (num != 0); | 83 | } while (num != 0); |
84 | |||
85 | if (overrun) | ||
86 | ir_raw_event_reset(kernel_ir->inp_dev); | ||
87 | else if (handle) | ||
88 | ir_raw_event_handle(kernel_ir->inp_dev); | ||
195 | } | 89 | } |
196 | 90 | ||
197 | void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events) | 91 | void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events) |
@@ -230,7 +124,7 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events) | |||
230 | } | 124 | } |
231 | 125 | ||
232 | if (data_available) | 126 | if (data_available) |
233 | cx23885_input_process_pulse_widths_rc5(dev, overrun); | 127 | cx23885_input_process_measurements(dev, overrun); |
234 | 128 | ||
235 | if (overrun) { | 129 | if (overrun) { |
236 | /* If there was a FIFO overrun, clear & restart the device */ | 130 | /* If there was a FIFO overrun, clear & restart the device */ |
@@ -241,34 +135,15 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events) | |||
241 | } | 135 | } |
242 | } | 136 | } |
243 | 137 | ||
244 | static void cx23885_input_ir_start(struct cx23885_dev *dev) | 138 | static int cx23885_input_ir_start(struct cx23885_dev *dev) |
245 | { | 139 | { |
246 | struct card_ir *ir_input = dev->ir_input; | ||
247 | struct ir_input_state *ir_input_state = &ir_input->ir; | ||
248 | struct v4l2_subdev_ir_parameters params; | 140 | struct v4l2_subdev_ir_parameters params; |
249 | 141 | ||
250 | if (dev->sd_ir == NULL) | 142 | if (dev->sd_ir == NULL) |
251 | return; | 143 | return -ENODEV; |
252 | 144 | ||
253 | atomic_set(&dev->ir_input_stopping, 0); | 145 | atomic_set(&dev->ir_input_stopping, 0); |
254 | 146 | ||
255 | /* keyup timer set up, if needed */ | ||
256 | switch (dev->board) { | ||
257 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
258 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
259 | setup_timer(&ir_input->timer_keyup, | ||
260 | ir_rc5_timer_keyup, /* Not actually RC-5 specific */ | ||
261 | (unsigned long) ir_input); | ||
262 | if (ir_input_state->ir_type == IR_TYPE_RC5) { | ||
263 | /* | ||
264 | * RC-5 repeats a held key every | ||
265 | * 64 bits * (2 * 32/36000) sec/bit = 113.778 ms | ||
266 | */ | ||
267 | ir_input->rc5_key_timeout = 115; | ||
268 | } | ||
269 | break; | ||
270 | } | ||
271 | |||
272 | v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, ¶ms); | 147 | v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, ¶ms); |
273 | switch (dev->board) { | 148 | switch (dev->board) { |
274 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | 149 | case CX23885_BOARD_HAUPPAUGE_HVR1850: |
@@ -299,11 +174,21 @@ static void cx23885_input_ir_start(struct cx23885_dev *dev) | |||
299 | break; | 174 | break; |
300 | } | 175 | } |
301 | v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, ¶ms); | 176 | v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, ¶ms); |
177 | return 0; | ||
178 | } | ||
179 | |||
180 | static int cx23885_input_ir_open(void *priv) | ||
181 | { | ||
182 | struct cx23885_kernel_ir *kernel_ir = priv; | ||
183 | |||
184 | if (kernel_ir->cx == NULL) | ||
185 | return -ENODEV; | ||
186 | |||
187 | return cx23885_input_ir_start(kernel_ir->cx); | ||
302 | } | 188 | } |
303 | 189 | ||
304 | static void cx23885_input_ir_stop(struct cx23885_dev *dev) | 190 | static void cx23885_input_ir_stop(struct cx23885_dev *dev) |
305 | { | 191 | { |
306 | struct card_ir *ir_input = dev->ir_input; | ||
307 | struct v4l2_subdev_ir_parameters params; | 192 | struct v4l2_subdev_ir_parameters params; |
308 | 193 | ||
309 | if (dev->sd_ir == NULL) | 194 | if (dev->sd_ir == NULL) |
@@ -327,21 +212,26 @@ static void cx23885_input_ir_stop(struct cx23885_dev *dev) | |||
327 | } | 212 | } |
328 | 213 | ||
329 | flush_scheduled_work(); | 214 | flush_scheduled_work(); |
215 | } | ||
330 | 216 | ||
331 | switch (dev->board) { | 217 | static void cx23885_input_ir_close(void *priv) |
332 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | 218 | { |
333 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | 219 | struct cx23885_kernel_ir *kernel_ir = priv; |
334 | del_timer_sync(&ir_input->timer_keyup); | 220 | |
335 | break; | 221 | if (kernel_ir->cx != NULL) |
336 | } | 222 | cx23885_input_ir_stop(kernel_ir->cx); |
337 | } | 223 | } |
338 | 224 | ||
339 | int cx23885_input_init(struct cx23885_dev *dev) | 225 | int cx23885_input_init(struct cx23885_dev *dev) |
340 | { | 226 | { |
341 | struct card_ir *ir; | 227 | struct cx23885_kernel_ir *kernel_ir; |
342 | struct input_dev *input_dev; | 228 | struct input_dev *inp_dev; |
343 | char *ir_codes = NULL; | 229 | struct ir_dev_props *props; |
344 | int ir_type, ir_addr, ir_start; | 230 | |
231 | char *rc_map; | ||
232 | enum rc_driver_type driver_type; | ||
233 | unsigned long allowed_protos; | ||
234 | |||
345 | int ret; | 235 | int ret; |
346 | 236 | ||
347 | /* | 237 | /* |
@@ -354,53 +244,59 @@ int cx23885_input_init(struct cx23885_dev *dev) | |||
354 | switch (dev->board) { | 244 | switch (dev->board) { |
355 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | 245 | case CX23885_BOARD_HAUPPAUGE_HVR1850: |
356 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | 246 | case CX23885_BOARD_HAUPPAUGE_HVR1290: |
357 | /* Parameters for the grey Hauppauge remote for the HVR-1850 */ | 247 | /* Integrated CX23888 IR controller */ |
358 | ir_codes = RC_MAP_HAUPPAUGE_NEW; | 248 | driver_type = RC_DRIVER_IR_RAW; |
359 | ir_type = IR_TYPE_RC5; | 249 | allowed_protos = IR_TYPE_ALL; |
360 | ir_addr = 0x1e; /* RC-5 system bits emitted by the remote */ | 250 | /* The grey Hauppauge RC-5 remote */ |
361 | ir_start = RC5_START_BITS_NORMAL; /* A basic RC-5 remote */ | 251 | rc_map = RC_MAP_RC5_HAUPPAUGE_NEW; |
362 | break; | 252 | break; |
363 | } | 253 | default: |
364 | if (ir_codes == NULL) | ||
365 | return -ENODEV; | 254 | return -ENODEV; |
366 | |||
367 | ir = kzalloc(sizeof(*ir), GFP_KERNEL); | ||
368 | input_dev = input_allocate_device(); | ||
369 | if (!ir || !input_dev) { | ||
370 | ret = -ENOMEM; | ||
371 | goto err_out_free; | ||
372 | } | 255 | } |
373 | 256 | ||
374 | ir->dev = input_dev; | 257 | /* cx23885 board instance kernel IR state */ |
375 | ir->addr = ir_addr; | 258 | kernel_ir = kzalloc(sizeof(struct cx23885_kernel_ir), GFP_KERNEL); |
376 | ir->start = ir_start; | 259 | if (kernel_ir == NULL) |
260 | return -ENOMEM; | ||
377 | 261 | ||
378 | /* init input device */ | 262 | kernel_ir->cx = dev; |
379 | snprintf(ir->name, sizeof(ir->name), "cx23885 IR (%s)", | 263 | kernel_ir->name = kasprintf(GFP_KERNEL, "cx23885 IR (%s)", |
380 | cx23885_boards[dev->board].name); | 264 | cx23885_boards[dev->board].name); |
381 | snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(dev->pci)); | 265 | kernel_ir->phys = kasprintf(GFP_KERNEL, "pci-%s/ir0", |
266 | pci_name(dev->pci)); | ||
382 | 267 | ||
383 | ret = ir_input_init(input_dev, &ir->ir, ir_type); | 268 | /* input device */ |
384 | if (ret < 0) | 269 | inp_dev = input_allocate_device(); |
270 | if (inp_dev == NULL) { | ||
271 | ret = -ENOMEM; | ||
385 | goto err_out_free; | 272 | goto err_out_free; |
273 | } | ||
386 | 274 | ||
387 | input_dev->name = ir->name; | 275 | kernel_ir->inp_dev = inp_dev; |
388 | input_dev->phys = ir->phys; | 276 | inp_dev->name = kernel_ir->name; |
389 | input_dev->id.bustype = BUS_PCI; | 277 | inp_dev->phys = kernel_ir->phys; |
390 | input_dev->id.version = 1; | 278 | inp_dev->id.bustype = BUS_PCI; |
279 | inp_dev->id.version = 1; | ||
391 | if (dev->pci->subsystem_vendor) { | 280 | if (dev->pci->subsystem_vendor) { |
392 | input_dev->id.vendor = dev->pci->subsystem_vendor; | 281 | inp_dev->id.vendor = dev->pci->subsystem_vendor; |
393 | input_dev->id.product = dev->pci->subsystem_device; | 282 | inp_dev->id.product = dev->pci->subsystem_device; |
394 | } else { | 283 | } else { |
395 | input_dev->id.vendor = dev->pci->vendor; | 284 | inp_dev->id.vendor = dev->pci->vendor; |
396 | input_dev->id.product = dev->pci->device; | 285 | inp_dev->id.product = dev->pci->device; |
397 | } | 286 | } |
398 | input_dev->dev.parent = &dev->pci->dev; | 287 | inp_dev->dev.parent = &dev->pci->dev; |
399 | 288 | ||
400 | dev->ir_input = ir; | 289 | /* kernel ir device properties */ |
401 | cx23885_input_ir_start(dev); | 290 | props = &kernel_ir->props; |
402 | 291 | props->driver_type = driver_type; | |
403 | ret = ir_input_register(ir->dev, ir_codes, NULL, MODULE_NAME); | 292 | props->allowed_protos = allowed_protos; |
293 | props->priv = kernel_ir; | ||
294 | props->open = cx23885_input_ir_open; | ||
295 | props->close = cx23885_input_ir_close; | ||
296 | |||
297 | /* Go */ | ||
298 | dev->kernel_ir = kernel_ir; | ||
299 | ret = ir_input_register(inp_dev, rc_map, props, MODULE_NAME); | ||
404 | if (ret) | 300 | if (ret) |
405 | goto err_out_stop; | 301 | goto err_out_stop; |
406 | 302 | ||
@@ -408,9 +304,12 @@ int cx23885_input_init(struct cx23885_dev *dev) | |||
408 | 304 | ||
409 | err_out_stop: | 305 | err_out_stop: |
410 | cx23885_input_ir_stop(dev); | 306 | cx23885_input_ir_stop(dev); |
411 | dev->ir_input = NULL; | 307 | dev->kernel_ir = NULL; |
308 | /* TODO: double check clean-up of kernel_ir->inp_dev */ | ||
412 | err_out_free: | 309 | err_out_free: |
413 | kfree(ir); | 310 | kfree(kernel_ir->phys); |
311 | kfree(kernel_ir->name); | ||
312 | kfree(kernel_ir); | ||
414 | return ret; | 313 | return ret; |
415 | } | 314 | } |
416 | 315 | ||
@@ -419,9 +318,11 @@ void cx23885_input_fini(struct cx23885_dev *dev) | |||
419 | /* Always stop the IR hardware from generating interrupts */ | 318 | /* Always stop the IR hardware from generating interrupts */ |
420 | cx23885_input_ir_stop(dev); | 319 | cx23885_input_ir_stop(dev); |
421 | 320 | ||
422 | if (dev->ir_input == NULL) | 321 | if (dev->kernel_ir == NULL) |
423 | return; | 322 | return; |
424 | ir_input_unregister(dev->ir_input->dev); | 323 | ir_input_unregister(dev->kernel_ir->inp_dev); |
425 | kfree(dev->ir_input); | 324 | kfree(dev->kernel_ir->phys); |
426 | dev->ir_input = NULL; | 325 | kfree(dev->kernel_ir->name); |
326 | kfree(dev->kernel_ir); | ||
327 | dev->kernel_ir = NULL; | ||
427 | } | 328 | } |