2014-04-04 07:34:28 +08:00
|
|
|
/* rc-ir-raw.c - handle IR pulse/space events
|
2010-03-21 07:59:44 +08:00
|
|
|
*
|
2014-02-07 18:03:07 +08:00
|
|
|
* Copyright (C) 2010 by Mauro Carvalho Chehab
|
2010-03-21 07:59:44 +08:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2011-08-02 03:26:38 +08:00
|
|
|
#include <linux/export.h>
|
2010-07-31 22:59:17 +08:00
|
|
|
#include <linux/kthread.h>
|
2010-07-31 22:59:16 +08:00
|
|
|
#include <linux/mutex.h>
|
2011-07-29 13:34:32 +08:00
|
|
|
#include <linux/kmod.h>
|
2010-04-09 00:10:00 +08:00
|
|
|
#include <linux/sched.h>
|
2010-07-31 22:59:17 +08:00
|
|
|
#include <linux/freezer.h>
|
2010-11-10 10:09:57 +08:00
|
|
|
#include "rc-core-priv.h"
|
2010-03-21 07:59:44 +08:00
|
|
|
|
2010-04-09 00:10:00 +08:00
|
|
|
/* Define the max number of pulse/space transitions to buffer */
|
|
|
|
#define MAX_IR_EVENT_SIZE 512
|
2010-03-21 07:59:44 +08:00
|
|
|
|
2010-06-14 04:29:36 +08:00
|
|
|
/* Used to keep track of IR raw clients, protected by ir_raw_handler_lock */
|
|
|
|
static LIST_HEAD(ir_raw_client_list);
|
|
|
|
|
2010-03-25 07:47:53 +08:00
|
|
|
/* Used to handle IR raw handler extensions */
|
2010-07-31 22:59:16 +08:00
|
|
|
static DEFINE_MUTEX(ir_raw_handler_lock);
|
2010-06-14 04:29:31 +08:00
|
|
|
static LIST_HEAD(ir_raw_handler_list);
|
|
|
|
static u64 available_protocols;
|
2015-04-01 01:48:10 +08:00
|
|
|
static u64 encode_protocols;
|
2010-03-26 08:13:43 +08:00
|
|
|
|
2010-07-31 22:59:17 +08:00
|
|
|
static int ir_raw_event_thread(void *data)
|
2010-04-09 00:10:00 +08:00
|
|
|
{
|
2010-04-16 05:46:00 +08:00
|
|
|
struct ir_raw_event ev;
|
2010-06-14 04:29:36 +08:00
|
|
|
struct ir_raw_handler *handler;
|
2010-07-31 22:59:17 +08:00
|
|
|
struct ir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data;
|
2010-09-07 05:26:06 +08:00
|
|
|
int retval;
|
2010-07-31 22:59:17 +08:00
|
|
|
|
|
|
|
while (!kthread_should_stop()) {
|
2010-04-09 00:10:00 +08:00
|
|
|
|
2010-09-07 05:26:06 +08:00
|
|
|
spin_lock_irq(&raw->lock);
|
2012-03-21 01:05:40 +08:00
|
|
|
retval = kfifo_len(&raw->kfifo);
|
2010-09-07 05:26:06 +08:00
|
|
|
|
2012-03-21 01:05:40 +08:00
|
|
|
if (retval < sizeof(ev)) {
|
2010-09-07 05:26:06 +08:00
|
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
2010-07-31 22:59:17 +08:00
|
|
|
|
2010-09-07 05:26:06 +08:00
|
|
|
if (kthread_should_stop())
|
|
|
|
set_current_state(TASK_RUNNING);
|
|
|
|
|
|
|
|
spin_unlock_irq(&raw->lock);
|
|
|
|
schedule();
|
|
|
|
continue;
|
2010-07-31 22:59:17 +08:00
|
|
|
}
|
|
|
|
|
2012-03-21 01:05:40 +08:00
|
|
|
retval = kfifo_out(&raw->kfifo, &ev, sizeof(ev));
|
2010-09-07 05:26:06 +08:00
|
|
|
spin_unlock_irq(&raw->lock);
|
2010-07-31 22:59:17 +08:00
|
|
|
|
2010-09-07 05:26:06 +08:00
|
|
|
mutex_lock(&ir_raw_handler_lock);
|
|
|
|
list_for_each_entry(handler, &ir_raw_handler_list, list)
|
2010-10-30 03:08:23 +08:00
|
|
|
handler->decode(raw->dev, ev);
|
2010-09-07 05:26:06 +08:00
|
|
|
raw->prev_ev = ev;
|
|
|
|
mutex_unlock(&ir_raw_handler_lock);
|
2010-06-14 04:29:36 +08:00
|
|
|
}
|
2010-07-31 22:59:17 +08:00
|
|
|
|
|
|
|
return 0;
|
2010-04-09 00:10:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ir_raw_event_store() - pass a pulse/space duration to the raw ir decoders
|
2010-10-30 03:08:23 +08:00
|
|
|
* @dev: the struct rc_dev device descriptor
|
2010-04-16 05:46:00 +08:00
|
|
|
* @ev: the struct ir_raw_event descriptor of the pulse/space
|
2010-04-09 00:10:00 +08:00
|
|
|
*
|
|
|
|
* This routine (which may be called from an interrupt context) stores a
|
|
|
|
* pulse/space duration for the raw ir decoding state machines. Pulses are
|
|
|
|
* signalled as positive values and spaces as negative values. A zero value
|
|
|
|
* will reset the decoding state machines.
|
|
|
|
*/
|
2010-10-30 03:08:23 +08:00
|
|
|
int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev)
|
2010-03-21 07:59:44 +08:00
|
|
|
{
|
2010-10-30 03:08:23 +08:00
|
|
|
if (!dev->raw)
|
2010-03-21 07:59:44 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2010-10-20 22:56:50 +08:00
|
|
|
IR_dprintk(2, "sample: (%05dus %s)\n",
|
2010-10-30 03:08:23 +08:00
|
|
|
TO_US(ev->duration), TO_STR(ev->pulse));
|
2010-07-31 22:59:15 +08:00
|
|
|
|
2010-10-30 03:08:23 +08:00
|
|
|
if (kfifo_in(&dev->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev))
|
2010-04-09 00:10:00 +08:00
|
|
|
return -ENOMEM;
|
2010-03-21 07:59:44 +08:00
|
|
|
|
2010-04-09 00:10:00 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(ir_raw_event_store);
|
2010-03-21 07:59:44 +08:00
|
|
|
|
2010-04-09 00:10:00 +08:00
|
|
|
/**
|
|
|
|
* ir_raw_event_store_edge() - notify raw ir decoders of the start of a pulse/space
|
2010-10-30 03:08:23 +08:00
|
|
|
* @dev: the struct rc_dev device descriptor
|
2010-04-09 00:10:00 +08:00
|
|
|
* @type: the type of the event that has occurred
|
|
|
|
*
|
|
|
|
* This routine (which may be called from an interrupt context) is used to
|
|
|
|
* store the beginning of an ir pulse or space (or the start/end of ir
|
|
|
|
* reception) for the raw ir decoding state machines. This is used by
|
|
|
|
* hardware which does not provide durations directly but only interrupts
|
|
|
|
* (or similar events) on state change.
|
|
|
|
*/
|
2010-10-30 03:08:23 +08:00
|
|
|
int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type)
|
2010-04-09 00:10:00 +08:00
|
|
|
{
|
|
|
|
ktime_t now;
|
|
|
|
s64 delta; /* ns */
|
2011-01-21 05:16:50 +08:00
|
|
|
DEFINE_IR_RAW_EVENT(ev);
|
2010-04-09 00:10:00 +08:00
|
|
|
int rc = 0;
|
2011-06-17 03:18:37 +08:00
|
|
|
int delay;
|
2010-03-21 07:59:44 +08:00
|
|
|
|
2010-10-30 03:08:23 +08:00
|
|
|
if (!dev->raw)
|
2010-04-09 00:10:00 +08:00
|
|
|
return -EINVAL;
|
2010-03-21 07:59:44 +08:00
|
|
|
|
2010-04-09 00:10:00 +08:00
|
|
|
now = ktime_get();
|
2010-10-30 03:08:23 +08:00
|
|
|
delta = ktime_to_ns(ktime_sub(now, dev->raw->last_event));
|
2011-06-17 03:18:37 +08:00
|
|
|
delay = MS_TO_NS(dev->input_dev->rep[REP_DELAY]);
|
2010-03-21 07:59:44 +08:00
|
|
|
|
2010-04-09 00:10:00 +08:00
|
|
|
/* Check for a long duration since last event or if we're
|
|
|
|
* being called for the first time, note that delta can't
|
|
|
|
* possibly be negative.
|
|
|
|
*/
|
2011-06-17 03:18:37 +08:00
|
|
|
if (delta > delay || !dev->raw->last_type)
|
2010-04-09 00:10:00 +08:00
|
|
|
type |= IR_START_EVENT;
|
2010-04-16 05:46:00 +08:00
|
|
|
else
|
|
|
|
ev.duration = delta;
|
2010-04-09 00:10:00 +08:00
|
|
|
|
|
|
|
if (type & IR_START_EVENT)
|
2010-10-30 03:08:23 +08:00
|
|
|
ir_raw_event_reset(dev);
|
|
|
|
else if (dev->raw->last_type & IR_SPACE) {
|
2010-04-16 05:46:00 +08:00
|
|
|
ev.pulse = false;
|
2010-10-30 03:08:23 +08:00
|
|
|
rc = ir_raw_event_store(dev, &ev);
|
|
|
|
} else if (dev->raw->last_type & IR_PULSE) {
|
2010-04-16 05:46:00 +08:00
|
|
|
ev.pulse = true;
|
2010-10-30 03:08:23 +08:00
|
|
|
rc = ir_raw_event_store(dev, &ev);
|
2010-04-16 05:46:00 +08:00
|
|
|
} else
|
2010-04-09 00:10:00 +08:00
|
|
|
return 0;
|
2010-03-21 07:59:44 +08:00
|
|
|
|
2010-10-30 03:08:23 +08:00
|
|
|
dev->raw->last_event = now;
|
|
|
|
dev->raw->last_type = type;
|
2010-03-21 07:59:44 +08:00
|
|
|
return rc;
|
|
|
|
}
|
2010-04-09 00:10:00 +08:00
|
|
|
EXPORT_SYMBOL_GPL(ir_raw_event_store_edge);
|
2010-03-21 07:59:44 +08:00
|
|
|
|
2010-07-31 22:59:22 +08:00
|
|
|
/**
|
|
|
|
* ir_raw_event_store_with_filter() - pass next pulse/space to decoders with some processing
|
2010-10-30 03:08:23 +08:00
|
|
|
* @dev: the struct rc_dev device descriptor
|
2010-07-31 22:59:22 +08:00
|
|
|
* @type: the type of the event that has occurred
|
|
|
|
*
|
|
|
|
* This routine (which may be called from an interrupt context) works
|
2011-03-31 09:57:33 +08:00
|
|
|
* in similar manner to ir_raw_event_store_edge.
|
2010-07-31 22:59:22 +08:00
|
|
|
* This routine is intended for devices with limited internal buffer
|
2012-08-13 19:59:47 +08:00
|
|
|
* It automerges samples of same type, and handles timeouts. Returns non-zero
|
|
|
|
* if the event was added, and zero if the event was ignored due to idle
|
|
|
|
* processing.
|
2010-07-31 22:59:22 +08:00
|
|
|
*/
|
2010-10-30 03:08:23 +08:00
|
|
|
int ir_raw_event_store_with_filter(struct rc_dev *dev, struct ir_raw_event *ev)
|
2010-07-31 22:59:22 +08:00
|
|
|
{
|
2010-10-30 03:08:23 +08:00
|
|
|
if (!dev->raw)
|
2010-07-31 22:59:22 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
/* Ignore spaces in idle mode */
|
2010-10-30 03:08:23 +08:00
|
|
|
if (dev->idle && !ev->pulse)
|
2010-07-31 22:59:22 +08:00
|
|
|
return 0;
|
2010-10-30 03:08:23 +08:00
|
|
|
else if (dev->idle)
|
|
|
|
ir_raw_event_set_idle(dev, false);
|
|
|
|
|
|
|
|
if (!dev->raw->this_ev.duration)
|
|
|
|
dev->raw->this_ev = *ev;
|
|
|
|
else if (ev->pulse == dev->raw->this_ev.pulse)
|
|
|
|
dev->raw->this_ev.duration += ev->duration;
|
|
|
|
else {
|
|
|
|
ir_raw_event_store(dev, &dev->raw->this_ev);
|
|
|
|
dev->raw->this_ev = *ev;
|
2010-07-31 22:59:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Enter idle mode if nessesary */
|
2010-10-30 03:08:23 +08:00
|
|
|
if (!ev->pulse && dev->timeout &&
|
|
|
|
dev->raw->this_ev.duration >= dev->timeout)
|
|
|
|
ir_raw_event_set_idle(dev, true);
|
|
|
|
|
2012-08-13 19:59:47 +08:00
|
|
|
return 1;
|
2010-07-31 22:59:22 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(ir_raw_event_store_with_filter);
|
|
|
|
|
2010-10-17 06:56:28 +08:00
|
|
|
/**
|
2010-10-30 03:08:23 +08:00
|
|
|
* ir_raw_event_set_idle() - provide hint to rc-core when the device is idle or not
|
|
|
|
* @dev: the struct rc_dev device descriptor
|
|
|
|
* @idle: whether the device is idle or not
|
2010-10-17 06:56:28 +08:00
|
|
|
*/
|
2010-10-30 03:08:23 +08:00
|
|
|
void ir_raw_event_set_idle(struct rc_dev *dev, bool idle)
|
2010-07-31 22:59:22 +08:00
|
|
|
{
|
2010-10-30 03:08:23 +08:00
|
|
|
if (!dev->raw)
|
2010-07-31 22:59:22 +08:00
|
|
|
return;
|
|
|
|
|
2010-10-17 06:56:28 +08:00
|
|
|
IR_dprintk(2, "%s idle mode\n", idle ? "enter" : "leave");
|
2010-07-31 22:59:22 +08:00
|
|
|
|
|
|
|
if (idle) {
|
2010-10-30 03:08:23 +08:00
|
|
|
dev->raw->this_ev.timeout = true;
|
|
|
|
ir_raw_event_store(dev, &dev->raw->this_ev);
|
|
|
|
init_ir_raw_event(&dev->raw->this_ev);
|
2010-07-31 22:59:22 +08:00
|
|
|
}
|
2010-10-17 06:56:28 +08:00
|
|
|
|
2010-10-30 03:08:23 +08:00
|
|
|
if (dev->s_idle)
|
|
|
|
dev->s_idle(dev, idle);
|
|
|
|
|
|
|
|
dev->idle = idle;
|
2010-07-31 22:59:22 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(ir_raw_event_set_idle);
|
|
|
|
|
2010-04-09 00:10:00 +08:00
|
|
|
/**
|
|
|
|
* ir_raw_event_handle() - schedules the decoding of stored ir data
|
2010-10-30 03:08:23 +08:00
|
|
|
* @dev: the struct rc_dev device descriptor
|
2010-04-09 00:10:00 +08:00
|
|
|
*
|
2010-10-30 03:08:23 +08:00
|
|
|
* This routine will tell rc-core to start decoding stored ir data.
|
2010-04-09 00:10:00 +08:00
|
|
|
*/
|
2010-10-30 03:08:23 +08:00
|
|
|
void ir_raw_event_handle(struct rc_dev *dev)
|
2010-03-21 07:59:44 +08:00
|
|
|
{
|
2010-09-07 05:26:06 +08:00
|
|
|
unsigned long flags;
|
2010-03-21 07:59:44 +08:00
|
|
|
|
2010-10-30 03:08:23 +08:00
|
|
|
if (!dev->raw)
|
2010-04-09 00:10:00 +08:00
|
|
|
return;
|
2010-03-21 07:59:44 +08:00
|
|
|
|
2010-10-30 03:08:23 +08:00
|
|
|
spin_lock_irqsave(&dev->raw->lock, flags);
|
|
|
|
wake_up_process(dev->raw->thread);
|
|
|
|
spin_unlock_irqrestore(&dev->raw->lock, flags);
|
2010-03-21 07:59:44 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(ir_raw_event_handle);
|
2010-03-25 07:47:53 +08:00
|
|
|
|
2010-06-14 04:29:31 +08:00
|
|
|
/* used internally by the sysfs interface */
|
|
|
|
u64
|
2011-01-09 11:53:53 +08:00
|
|
|
ir_raw_get_allowed_protocols(void)
|
2010-06-14 04:29:31 +08:00
|
|
|
{
|
|
|
|
u64 protocols;
|
2010-07-31 22:59:16 +08:00
|
|
|
mutex_lock(&ir_raw_handler_lock);
|
2010-06-14 04:29:31 +08:00
|
|
|
protocols = available_protocols;
|
2010-07-31 22:59:16 +08:00
|
|
|
mutex_unlock(&ir_raw_handler_lock);
|
2010-06-14 04:29:31 +08:00
|
|
|
return protocols;
|
|
|
|
}
|
|
|
|
|
2015-04-01 01:48:10 +08:00
|
|
|
/* used internally by the sysfs interface */
|
|
|
|
u64
|
|
|
|
ir_raw_get_encode_protocols(void)
|
|
|
|
{
|
|
|
|
u64 protocols;
|
|
|
|
|
|
|
|
mutex_lock(&ir_raw_handler_lock);
|
|
|
|
protocols = encode_protocols;
|
|
|
|
mutex_unlock(&ir_raw_handler_lock);
|
|
|
|
return protocols;
|
|
|
|
}
|
|
|
|
|
2014-04-04 07:32:16 +08:00
|
|
|
static int change_protocol(struct rc_dev *dev, u64 *rc_type)
|
|
|
|
{
|
|
|
|
/* the caller will update dev->enabled_protocols */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-04-01 01:48:07 +08:00
|
|
|
/**
|
|
|
|
* ir_raw_gen_manchester() - Encode data with Manchester (bi-phase) modulation.
|
|
|
|
* @ev: Pointer to pointer to next free event. *@ev is incremented for
|
|
|
|
* each raw event filled.
|
|
|
|
* @max: Maximum number of raw events to fill.
|
|
|
|
* @timings: Manchester modulation timings.
|
|
|
|
* @n: Number of bits of data.
|
|
|
|
* @data: Data bits to encode.
|
|
|
|
*
|
|
|
|
* Encodes the @n least significant bits of @data using Manchester (bi-phase)
|
|
|
|
* modulation with the timing characteristics described by @timings, writing up
|
|
|
|
* to @max raw IR events using the *@ev pointer.
|
|
|
|
*
|
|
|
|
* Returns: 0 on success.
|
|
|
|
* -ENOBUFS if there isn't enough space in the array to fit the
|
|
|
|
* full encoded data. In this case all @max events will have been
|
|
|
|
* written.
|
|
|
|
*/
|
|
|
|
int ir_raw_gen_manchester(struct ir_raw_event **ev, unsigned int max,
|
|
|
|
const struct ir_raw_timings_manchester *timings,
|
|
|
|
unsigned int n, unsigned int data)
|
|
|
|
{
|
|
|
|
bool need_pulse;
|
|
|
|
unsigned int i;
|
|
|
|
int ret = -ENOBUFS;
|
|
|
|
|
|
|
|
i = 1 << (n - 1);
|
|
|
|
|
|
|
|
if (timings->leader) {
|
|
|
|
if (!max--)
|
|
|
|
return ret;
|
|
|
|
if (timings->pulse_space_start) {
|
|
|
|
init_ir_raw_event_duration((*ev)++, 1, timings->leader);
|
|
|
|
|
|
|
|
if (!max--)
|
|
|
|
return ret;
|
|
|
|
init_ir_raw_event_duration((*ev), 0, timings->leader);
|
|
|
|
} else {
|
|
|
|
init_ir_raw_event_duration((*ev), 1, timings->leader);
|
|
|
|
}
|
|
|
|
i >>= 1;
|
|
|
|
} else {
|
|
|
|
/* continue existing signal */
|
|
|
|
--(*ev);
|
|
|
|
}
|
|
|
|
/* from here on *ev will point to the last event rather than the next */
|
|
|
|
|
|
|
|
while (n && i > 0) {
|
|
|
|
need_pulse = !(data & i);
|
|
|
|
if (timings->invert)
|
|
|
|
need_pulse = !need_pulse;
|
|
|
|
if (need_pulse == !!(*ev)->pulse) {
|
|
|
|
(*ev)->duration += timings->clock;
|
|
|
|
} else {
|
|
|
|
if (!max--)
|
|
|
|
goto nobufs;
|
|
|
|
init_ir_raw_event_duration(++(*ev), need_pulse,
|
|
|
|
timings->clock);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!max--)
|
|
|
|
goto nobufs;
|
|
|
|
init_ir_raw_event_duration(++(*ev), !need_pulse,
|
|
|
|
timings->clock);
|
|
|
|
i >>= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (timings->trailer_space) {
|
|
|
|
if (!(*ev)->pulse)
|
|
|
|
(*ev)->duration += timings->trailer_space;
|
|
|
|
else if (!max--)
|
|
|
|
goto nobufs;
|
|
|
|
else
|
|
|
|
init_ir_raw_event_duration(++(*ev), 0,
|
|
|
|
timings->trailer_space);
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
nobufs:
|
|
|
|
/* point to the next event rather than last event before returning */
|
|
|
|
++(*ev);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(ir_raw_gen_manchester);
|
|
|
|
|
2015-04-01 01:48:06 +08:00
|
|
|
/**
|
|
|
|
* ir_raw_encode_scancode() - Encode a scancode as raw events
|
|
|
|
*
|
|
|
|
* @protocols: permitted protocols
|
|
|
|
* @scancode: scancode filter describing a single scancode
|
|
|
|
* @events: array of raw events to write into
|
|
|
|
* @max: max number of raw events
|
|
|
|
*
|
|
|
|
* Attempts to encode the scancode as raw events.
|
|
|
|
*
|
|
|
|
* Returns: The number of events written.
|
|
|
|
* -ENOBUFS if there isn't enough space in the array to fit the
|
|
|
|
* encoding. In this case all @max events will have been written.
|
|
|
|
* -EINVAL if the scancode is ambiguous or invalid, or if no
|
|
|
|
* compatible encoder was found.
|
|
|
|
*/
|
|
|
|
int ir_raw_encode_scancode(u64 protocols,
|
|
|
|
const struct rc_scancode_filter *scancode,
|
|
|
|
struct ir_raw_event *events, unsigned int max)
|
|
|
|
{
|
|
|
|
struct ir_raw_handler *handler;
|
|
|
|
int ret = -EINVAL;
|
|
|
|
|
|
|
|
mutex_lock(&ir_raw_handler_lock);
|
|
|
|
list_for_each_entry(handler, &ir_raw_handler_list, list) {
|
|
|
|
if (handler->protocols & protocols && handler->encode) {
|
|
|
|
ret = handler->encode(protocols, scancode, events, max);
|
|
|
|
if (ret >= 0 || ret == -ENOBUFS)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mutex_unlock(&ir_raw_handler_lock);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(ir_raw_encode_scancode);
|
|
|
|
|
2010-06-14 04:29:31 +08:00
|
|
|
/*
|
|
|
|
* Used to (un)register raw event clients
|
|
|
|
*/
|
2010-10-30 03:08:23 +08:00
|
|
|
int ir_raw_event_register(struct rc_dev *dev)
|
2010-06-14 04:29:31 +08:00
|
|
|
{
|
|
|
|
int rc;
|
2010-06-14 04:29:36 +08:00
|
|
|
struct ir_raw_handler *handler;
|
2010-06-14 04:29:31 +08:00
|
|
|
|
2010-10-30 03:08:23 +08:00
|
|
|
if (!dev)
|
|
|
|
return -EINVAL;
|
2010-06-14 04:29:31 +08:00
|
|
|
|
2010-10-30 03:08:23 +08:00
|
|
|
dev->raw = kzalloc(sizeof(*dev->raw), GFP_KERNEL);
|
|
|
|
if (!dev->raw)
|
|
|
|
return -ENOMEM;
|
2010-07-31 22:59:17 +08:00
|
|
|
|
2010-10-30 03:08:23 +08:00
|
|
|
dev->raw->dev = dev;
|
2014-04-04 07:32:16 +08:00
|
|
|
dev->change_protocol = change_protocol;
|
2010-10-30 03:08:23 +08:00
|
|
|
rc = kfifo_alloc(&dev->raw->kfifo,
|
|
|
|
sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE,
|
2010-06-14 04:29:31 +08:00
|
|
|
GFP_KERNEL);
|
2010-10-30 03:08:23 +08:00
|
|
|
if (rc < 0)
|
|
|
|
goto out;
|
2010-06-14 04:29:31 +08:00
|
|
|
|
2010-10-30 03:08:23 +08:00
|
|
|
spin_lock_init(&dev->raw->lock);
|
|
|
|
dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw,
|
|
|
|
"rc%ld", dev->devno);
|
2010-07-31 22:59:17 +08:00
|
|
|
|
2010-10-30 03:08:23 +08:00
|
|
|
if (IS_ERR(dev->raw->thread)) {
|
|
|
|
rc = PTR_ERR(dev->raw->thread);
|
|
|
|
goto out;
|
2010-07-31 22:59:17 +08:00
|
|
|
}
|
|
|
|
|
2010-07-31 22:59:16 +08:00
|
|
|
mutex_lock(&ir_raw_handler_lock);
|
2010-10-30 03:08:23 +08:00
|
|
|
list_add_tail(&dev->raw->list, &ir_raw_client_list);
|
2010-06-14 04:29:36 +08:00
|
|
|
list_for_each_entry(handler, &ir_raw_handler_list, list)
|
|
|
|
if (handler->raw_register)
|
2010-10-30 03:08:23 +08:00
|
|
|
handler->raw_register(dev);
|
2010-07-31 22:59:16 +08:00
|
|
|
mutex_unlock(&ir_raw_handler_lock);
|
2010-06-14 04:29:31 +08:00
|
|
|
|
2010-06-14 04:29:36 +08:00
|
|
|
return 0;
|
2010-10-30 03:08:23 +08:00
|
|
|
|
|
|
|
out:
|
|
|
|
kfree(dev->raw);
|
|
|
|
dev->raw = NULL;
|
|
|
|
return rc;
|
2010-06-14 04:29:31 +08:00
|
|
|
}
|
|
|
|
|
2010-10-30 03:08:23 +08:00
|
|
|
void ir_raw_event_unregister(struct rc_dev *dev)
|
2010-06-14 04:29:31 +08:00
|
|
|
{
|
2010-06-14 04:29:36 +08:00
|
|
|
struct ir_raw_handler *handler;
|
2010-06-14 04:29:31 +08:00
|
|
|
|
2010-10-30 03:08:23 +08:00
|
|
|
if (!dev || !dev->raw)
|
2010-06-14 04:29:31 +08:00
|
|
|
return;
|
|
|
|
|
2010-10-30 03:08:23 +08:00
|
|
|
kthread_stop(dev->raw->thread);
|
2010-06-14 04:29:36 +08:00
|
|
|
|
2010-07-31 22:59:16 +08:00
|
|
|
mutex_lock(&ir_raw_handler_lock);
|
2010-10-30 03:08:23 +08:00
|
|
|
list_del(&dev->raw->list);
|
2010-06-14 04:29:36 +08:00
|
|
|
list_for_each_entry(handler, &ir_raw_handler_list, list)
|
|
|
|
if (handler->raw_unregister)
|
2010-10-30 03:08:23 +08:00
|
|
|
handler->raw_unregister(dev);
|
2010-07-31 22:59:16 +08:00
|
|
|
mutex_unlock(&ir_raw_handler_lock);
|
2010-06-14 04:29:31 +08:00
|
|
|
|
2010-10-30 03:08:23 +08:00
|
|
|
kfifo_free(&dev->raw->kfifo);
|
|
|
|
kfree(dev->raw);
|
|
|
|
dev->raw = NULL;
|
2010-06-14 04:29:31 +08:00
|
|
|
}
|
|
|
|
|
2010-03-25 07:47:53 +08:00
|
|
|
/*
|
|
|
|
* Extension interface - used to register the IR decoders
|
|
|
|
*/
|
|
|
|
|
|
|
|
int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler)
|
|
|
|
{
|
2010-06-14 04:29:36 +08:00
|
|
|
struct ir_raw_event_ctrl *raw;
|
|
|
|
|
2010-07-31 22:59:16 +08:00
|
|
|
mutex_lock(&ir_raw_handler_lock);
|
2010-03-25 07:47:53 +08:00
|
|
|
list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list);
|
2010-06-14 04:29:36 +08:00
|
|
|
if (ir_raw_handler->raw_register)
|
|
|
|
list_for_each_entry(raw, &ir_raw_client_list, list)
|
2010-10-30 03:08:23 +08:00
|
|
|
ir_raw_handler->raw_register(raw->dev);
|
2010-06-14 04:29:31 +08:00
|
|
|
available_protocols |= ir_raw_handler->protocols;
|
2015-04-01 01:48:10 +08:00
|
|
|
if (ir_raw_handler->encode)
|
|
|
|
encode_protocols |= ir_raw_handler->protocols;
|
2010-07-31 22:59:16 +08:00
|
|
|
mutex_unlock(&ir_raw_handler_lock);
|
2010-06-14 04:29:31 +08:00
|
|
|
|
2010-03-25 07:47:53 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(ir_raw_handler_register);
|
|
|
|
|
|
|
|
void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
|
|
|
|
{
|
2010-06-14 04:29:36 +08:00
|
|
|
struct ir_raw_event_ctrl *raw;
|
|
|
|
|
2010-07-31 22:59:16 +08:00
|
|
|
mutex_lock(&ir_raw_handler_lock);
|
2010-03-25 07:47:53 +08:00
|
|
|
list_del(&ir_raw_handler->list);
|
2010-06-14 04:29:36 +08:00
|
|
|
if (ir_raw_handler->raw_unregister)
|
|
|
|
list_for_each_entry(raw, &ir_raw_client_list, list)
|
2010-10-30 03:08:23 +08:00
|
|
|
ir_raw_handler->raw_unregister(raw->dev);
|
2010-06-14 04:29:31 +08:00
|
|
|
available_protocols &= ~ir_raw_handler->protocols;
|
2015-04-01 01:48:10 +08:00
|
|
|
if (ir_raw_handler->encode)
|
|
|
|
encode_protocols &= ~ir_raw_handler->protocols;
|
2010-07-31 22:59:16 +08:00
|
|
|
mutex_unlock(&ir_raw_handler_lock);
|
2010-03-25 07:47:53 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(ir_raw_handler_unregister);
|
|
|
|
|
2012-12-14 18:02:48 +08:00
|
|
|
void ir_raw_init(void)
|
2010-03-25 07:47:53 +08:00
|
|
|
{
|
|
|
|
/* Load the decoder modules */
|
|
|
|
|
|
|
|
load_nec_decode();
|
2010-04-04 21:27:20 +08:00
|
|
|
load_rc5_decode();
|
2010-04-09 07:04:40 +08:00
|
|
|
load_rc6_decode();
|
2010-04-16 05:46:05 +08:00
|
|
|
load_jvc_decode();
|
2010-04-16 05:46:10 +08:00
|
|
|
load_sony_decode();
|
2011-11-23 23:04:08 +08:00
|
|
|
load_sanyo_decode();
|
2014-02-06 06:15:16 +08:00
|
|
|
load_sharp_decode();
|
[media] rc-core support for Microsoft IR keyboard/mouse
This is a custom IR protocol decoder, for the RC-6-ish protocol used by
the Microsoft Remote Keyboard, apparently developed internally at
Microsoft, and officially dubbed MCIR-2, per their March 2011 remote and
transceiver requirements and specifications document, which also touches
on this IR keyboard/mouse device.
Its a standard keyboard with embedded thumb stick mouse pointer and
mouse buttons, along with a number of media keys. The media keys are
standard RC-6, identical to the signals from the stock MCE remotes, and
will be handled as such. The keyboard and mouse signals will be decoded
and delivered to the system by an input device registered specifically
by this driver.
Successfully tested with multiple mceusb-driven transceivers, as well as
with fintek-cir and redrat3 hardware. Essentially, any raw IR hardware
with enough sampling resolution should be able to use this decoder,
nothing about it is at all receiver-hardware-specific.
This work is inspired by lirc_mod_mce:
The documentation there and code aided in understanding and decoding the
protocol, but the bulk of the code is actually borrowed more from the
existing in-kernel decoders than anything. I did recycle the keyboard
keycode table, a few defines, and some of the keyboard and mouse data
parsing bits from lirc_mod_mce though.
Special thanks to James Meyer for providing the hardware, and being
patient with me as I took forever to get around to writing this.
callback routine to ensure we don't get any stuck keys, and used
symbolic names for the keytable. Also cc'ing Florian this time, who I
believe is the original mod-mce author...
CC: Florian Demski <fdemski@users.sourceforge.net>
Signed-off-by: Jarod Wilson <jarod@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
2011-07-14 05:09:48 +08:00
|
|
|
load_mce_kbd_decode();
|
2010-07-03 12:07:53 +08:00
|
|
|
load_lirc_codec();
|
2014-07-27 04:28:26 +08:00
|
|
|
load_xmp_decode();
|
2010-03-25 07:47:53 +08:00
|
|
|
|
|
|
|
/* If needed, we may later add some init code. In this case,
|
2010-11-18 00:28:38 +08:00
|
|
|
it is needed to change the CONFIG_MODULE test at rc-core.h
|
2010-03-25 07:47:53 +08:00
|
|
|
*/
|
|
|
|
}
|