驱动_IR驱动框架
平台:全志A40I
源码:Android 7.1 Linux 3.10
路径:linux-3.10/drivers/media/rc
接收驱动: sunxi-ir-dev.c
rc-sunxi-keymaps.c
核心层 : rc-core : rc-main.o
ir-raw.o
编码格式: ir-nec-decoder.c
键值映射表:rc-sunxi-keymaps.c
Android对应键值映射表:androidout argetproducta40-p1systemusrkeylayout Generic.kl
androiddevicesoftwinnera40-p1configs
sunxi-ir-dev.c
/* Copyright (C) 2014 ALLWINNERTECH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/irq.h>
#include <linux/of_platform.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <media/rc-core.h>
#include "sunxi-ir-rx.h"
#define SUNXI_IR_DRIVER_NAME "sunxi-rc-recv"
#define SUNXI_IR_DEVICE_NAME "sunxi_ir_recv"
#define RC5_UNIT 889000 /* ns */
DEFINE_IR_RAW_EVENT(rawir);
static struct sunxi_ir_data *ir_data;
static struct rc_dev *sunxi_rcdev;
static u32 is_receiving = 0;
static bool pluse_pre = 0;
static char ir_dev_name[] = "s_cir_rx";
static int debug_mask = 0;
#define dprintk(level_mask, fmt, arg...) if (unlikely(debug_mask & level_mask))
printk(fmt , ## arg)
#define IR_BASE (ir_data->reg_base)
static inline u8 ir_get_data(void)
{
return (u8)(readl(IR_BASE + IR_RXDAT_REG) & 0xff);
}
static inline u32 ir_get_intsta(void)
{
return (readl(IR_BASE + IR_RXINTS_REG));
}
static inline void ir_clr_intsta(u32 bitmap)
{
u32 tmp = readl(IR_BASE + IR_RXINTS_REG);
tmp &= ~0xff;
tmp |= bitmap&0xff;
writel(tmp, IR_BASE + IR_RXINTS_REG);
}
#ifdef CONFIG_OF
/* Translate OpenFirmware node properties into platform_data */
static struct of_device_id sunxi_ir_recv_of_match[] = {
{ .compatible = "allwinner,s_cir", },
{ .compatible = "allwinner,ir", },
{ },
};
MODULE_DEVICE_TABLE(of, sunxi_ir_recv_of_match);
#else /* !CONFIG_OF */
#endif
static void sunxi_ir_recv(u32 reg_data)
{
bool pluse_now = 0;
u32 ir_duration = 0;
pluse_now = reg_data >> 7; /* get the polarity */
ir_duration = reg_data & 0x7f; /* get duration, number of clocks */
if (pluse_pre == pluse_now) {
/* the signal sunperposition */
rawir.duration += ir_duration;
dprintk(DEBUG_INT, "raw: polar=%d; dur=%d
",
pluse_now, ir_duration);
} else {
#ifdef CONFIG_IR_RC5
rawir.duration *= IR_SIMPLE_UNIT;
dprintk(DEBUG_INT, "pusle :polar=%d, dur: %u ns
",
rawir.pulse, rawir.duration);
if ((rawir.duration > (RC5_UNIT + RC5_UNIT/2))
&& (rawir.duration < (2*RC5_UNIT + RC5_UNIT/2))) {
rawir.duration = rawir.duration/2;
ir_raw_event_store(sunxi_rcdev, &rawir);
ir_raw_event_store(sunxi_rcdev, &rawir);
} else
ir_raw_event_store(sunxi_rcdev, &rawir);
rawir.pulse = pluse_now;
rawir.duration = ir_duration;
dprintk(DEBUG_INT, "raw: polar=%d; dur=%d
",
pluse_now, ir_duration);
#else
if (is_receiving) {
rawir.duration *= IR_SIMPLE_UNIT;
dprintk(DEBUG_INT, "pusle :polar=%d, dur: %u ns
",
rawir.pulse, rawir.duration);
ir_raw_event_store(sunxi_rcdev, &rawir);
rawir.pulse = pluse_now;
rawir.duration = ir_duration;
dprintk(DEBUG_INT, "raw: polar=%d; dur=%d
",
pluse_now, ir_duration);
} else {
/* get the first pluse signal */
rawir.pulse = pluse_now;
rawir.duration = ir_duration;
/* Since IR hardware will cut Active Threshold time,
* So just add comeback */
rawir.duration += ((IR_ACTIVE_T>>16)+1) * ((IR_ACTIVE_T_C>>23) ? 128 : 1);
is_receiving = 1;
dprintk(DEBUG_INT, "get frist pulse,add head %d !!
",
((IR_ACTIVE_T>>16)+1) * ((IR_ACTIVE_T_C>>23) ? 128 : 1));
dprintk(DEBUG_INT, "raw: polar=%d; dur=%d
",
pluse_now, ir_duration);
}
#endif
pluse_pre = pluse_now;
}
}
static irqreturn_t sunxi_ir_recv_irq(int irq, void *dev_id)
{
u32 intsta,dcnt;
u32 i = 0;
u32 reg_data;
// printk("_____sunxi_ir_recv_irq ok
! ");
dprintk(DEBUG_INT, "IR RX IRQ Serve
");
intsta = ir_get_intsta();
ir_clr_intsta(intsta);
/* get the count of signal */
dcnt = (intsta>>8) & 0x7f;
dprintk(DEBUG_INT, "receive cnt :%d
", dcnt);
/* Read FIFO and fill the raw event */
for (i=0; i<dcnt; i++) {
/* get the data from fifo */
reg_data = ir_get_data();
/* Byte in FIFO format YXXXXXXX(B) Y:polarity(0:low level, 1:high level) X:Number of clocks */
sunxi_ir_recv(reg_data);
}
if (intsta & IR_RXINTS_RXPE) {
/* The last pulse can not call ir_raw_event_store()
* since miss invert level in above, manu call */
if (rawir.duration) {
rawir.duration *= IR_SIMPLE_UNIT;
dprintk(DEBUG_INT, "pusle :polar=%d, dur: %u ns
",
rawir.pulse, rawir.duration);
ir_raw_event_store(sunxi_rcdev, &rawir);
}
dprintk(DEBUG_INT, "handle raw data.
");
/* handle ther decoder theread */
ir_raw_event_handle(sunxi_rcdev);
is_receiving = 0;
pluse_pre = false;
}
if (intsta & IR_RXINTS_RXOF) {
/* FIFO Overflow */
pr_err("ir_rx_irq_service: Rx FIFO Overflow!!
");
is_receiving = 0;
pluse_pre = false;
}
return IRQ_HANDLED;
}
static void ir_mode_set(enum ir_mode set_mode)
{
u32 ctrl_reg = 0;
switch (set_mode) {
case CIR_MODE_ENABLE:
ctrl_reg = readl(IR_BASE+IR_CTRL_REG);
ctrl_reg |= IR_CIR_MODE;
break;
case IR_MODULE_ENABLE:
ctrl_reg = readl(IR_BASE+IR_CTRL_REG);
ctrl_reg |= IR_ENTIRE_ENABLE;
break;
case IR_BOTH_PULSE_MODE:
ctrl_reg = readl(IR_BASE+IR_CTRL_REG);
ctrl_reg |= IR_BOTH_PULSE;
break;
case IR_LOW_PULSE_MODE:
ctrl_reg = readl(IR_BASE+IR_CTRL_REG);
ctrl_reg |= IR_LOW_PULSE;
break;
case IR_HIGH_PULSE_MODE:
ctrl_reg = readl(IR_BASE+IR_CTRL_REG);
ctrl_reg |= IR_HIGH_PULSE;
break;
default:
pr_err("ir_mode_set error!!
");
return;
}
writel(ctrl_reg, IR_BASE+IR_CTRL_REG);
}
static void ir_sample_config(enum ir_sample_config set_sample)
{
u32 sample_reg = 0;
sample_reg = readl(IR_BASE+IR_SPLCFG_REG);
switch (set_sample) {
case IR_SAMPLE_REG_CLEAR:
sample_reg = 0;
break;
case IR_CLK_SAMPLE:
sample_reg |= IR_SAMPLE_DEV;
break;
case IR_FILTER_TH:
#ifdef CONFIG_IR_RC5
sample_reg |= IR_RXFILT_VAL_RC5;
#else
sample_reg |= IR_RXFILT_VAL;
#endif
break;
case IR_IDLE_TH:
sample_reg |= IR_RXIDLE_VAL;
break;
case IR_ACTIVE_TH:
sample_reg |= IR_ACTIVE_T;
sample_reg |= IR_ACTIVE_T_C;
break;
case IR_ACTIVE_TH_SAMPLE:
sample_reg |= IR_ACTIVE_T_SAMPLE;
sample_reg &= ~IR_ACTIVE_T_C;
break;
default:
return;
}
writel(sample_reg, IR_BASE+IR_SPLCFG_REG);
}
static void ir_signal_invert(void)
{
u32 reg_value;
reg_value = 0x1<<2;
writel(reg_value, IR_BASE+IR_RXCFG_REG);
}
static void ir_irq_config(enum ir_irq_config set_irq)
{
u32 irq_reg = 0;
switch (set_irq) {
case IR_IRQ_STATUS_CLEAR:
writel(0xef, IR_BASE+IR_RXINTS_REG);
return;
case IR_IRQ_ENABLE:
irq_reg = readl(IR_BASE+IR_RXINTE_REG);
irq_reg |= IR_IRQ_STATUS;
break;
case IR_IRQ_FIFO_SIZE:
irq_reg = readl(IR_BASE+IR_RXINTE_REG);
irq_reg |= IR_FIFO_20;
break;
default:
return;
}
writel(irq_reg, IR_BASE+IR_RXINTE_REG);
}
static void ir_reg_cfg(void)
{
/* Enable IR Mode */
ir_mode_set(CIR_MODE_ENABLE);
/* Config IR Smaple Register */
ir_sample_config(IR_SAMPLE_REG_CLEAR);
ir_sample_config(IR_CLK_SAMPLE);
ir_sample_config(IR_FILTER_TH); /* Set Filter Threshold */
ir_sample_config(IR_IDLE_TH); /* Set Idle Threshold */
#ifdef CONFIG_IR_RC5
ir_sample_config(IR_ACTIVE_TH_SAMPLE); /* rc5 Set Active Threshold */
/* Invert Input Signal */
#else
ir_sample_config(IR_ACTIVE_TH); /* Set Active Threshold */
#endif
ir_signal_invert();
/* Clear All Rx Interrupt Status */
ir_irq_config(IR_IRQ_STATUS_CLEAR);
/* Set Rx Interrupt Enable */
ir_irq_config(IR_IRQ_ENABLE);
ir_irq_config(IR_IRQ_FIFO_SIZE); /* Rx FIFO Threshold = FIFOsz/2; */
/* for NEC decode which start with high level in the header so should
* use IR_HIGH_PULSE_MODE mode, but some ICs don't support this function
* therefor use IR_BOTH_PULSE_MODE mode as default
*/
ir_mode_set(IR_BOTH_PULSE_MODE);
/* Enable IR Module */
ir_mode_set(IR_MODULE_ENABLE);
return;
}
static void ir_clk_cfg(void)
{
unsigned long rate = 0;
rate = clk_get_rate(ir_data->pclk);
dprintk(DEBUG_INT, "%s: get ir parent rate %dHZ
", __func__, (__u32)rate);
if(clk_set_parent(ir_data->mclk, ir_data->pclk))
pr_err("%s: set ir_clk parent failed!
", __func__);
if (clk_set_rate(ir_data->mclk, IR_CLK)) {
pr_err("set ir clock freq to %d failed!
", IR_CLK);
}
rate = clk_get_rate(ir_data->mclk);
dprintk(DEBUG_INT, "%s: get ir_clk rate %dHZ
", __func__, (__u32)rate);
if (clk_prepare_enable(ir_data->mclk)) {
pr_err("try to enable ir_clk failed!
");
}
return;
}
static void ir_clk_uncfg(void)
{
if(NULL == ir_data->mclk || IS_ERR(ir_data->mclk)) {
pr_err("ir_clk handle is invalid, just return!
");
return;
} else {
clk_disable_unprepare(ir_data->mclk);
clk_put(ir_data->mclk);
ir_data->mclk = NULL;
}
if(NULL == ir_data->pclk || IS_ERR(ir_data->pclk)) {
pr_err("ir_clk_source handle is invalid, just return!
");
return;
} else {
clk_put(ir_data->pclk);
ir_data->pclk = NULL;
}
return;
}
static void ir_setup(void)
{
dprintk(DEBUG_INIT, "ir_rx_setup: ir setup start!!
");
ir_clk_cfg();
ir_reg_cfg();
dprintk(DEBUG_INIT, "ir_rx_setup: ir setup end!!
");
return;
}
static int sunxi_ir_startup(struct platform_device *pdev)
{
struct device_node *np =NULL;
int i, ret = 0;
char addr_name[32];
const char *name = NULL;
ir_data = kzalloc(sizeof(*ir_data), GFP_KERNEL);
if (IS_ERR_OR_NULL(ir_data)) {
pr_err("ir_data: not enough memory for ir data
");
return -ENOMEM;
}
np = pdev->dev.of_node;
ir_data->reg_base= of_iomap(np, 0);
if (NULL == ir_data->reg_base) {
pr_err("%s:Failed to ioremap() io memory region.
",__func__);
ret = -EBUSY;
}else
dprintk(DEBUG_INIT, "ir base: %p !
",ir_data->reg_base);
ir_data->irq_num= irq_of_parse_and_map(np, 0);
if (0 == ir_data->irq_num) {
pr_err("%s:Failed to map irq.
", __func__);
ret = -EBUSY;
}else
dprintk(DEBUG_INIT, "ir irq num: %d !
",ir_data->irq_num);
ir_data->pclk = of_clk_get(np, 0);
ir_data->mclk = of_clk_get(np, 1);
if (NULL==ir_data->pclk||IS_ERR(ir_data->pclk)
||NULL==ir_data->mclk||IS_ERR(ir_data->mclk)) {
pr_err("%s:Failed to get clk.
", __func__);
ret = -EBUSY;
}
if (of_property_read_u32(np, "ir_addr_cnt", &ir_data->ir_addr_cnt)) {
pr_err("%s: get cir addr cnt failed", __func__);
ret = -EBUSY;
}
if(ir_data->ir_addr_cnt > MAX_ADDR_NUM)
ir_data->ir_addr_cnt = MAX_ADDR_NUM;
for(i = 0; i < ir_data->ir_addr_cnt; i++){
sprintf(addr_name, "ir_addr_code%d", i);
if (of_property_read_u32(np, (const char *)&addr_name,
&ir_data->ir_addr[i])) {
pr_err("node %s get failed!
", name);
ret = -EBUSY;
}
}
if (of_property_read_u32(np, "supply_vol", &ir_data->suply_vol)) {
pr_err("%s: get cir supply_vol failed", __func__);
}
if (of_property_read_string(np, "supply", &name)) {
pr_err("%s: cir have no power supply
", __func__);
} else {
ir_data->suply = regulator_get(NULL, name);
if(IS_ERR(ir_data->suply)){
pr_err("%s: cir get supply err
", __func__);
ir_data->suply = NULL;
}
}
return ret;
}
static int sunxi_ir_recv_probe(struct platform_device *pdev)
{
int rc;
// printk("_____sunxi_ir_recv_probe_____ ok !
");
// struct input_dev *input;
dprintk(DEBUG_INIT, "sunxi-ir probe start !
");
if (pdev->dev.of_node) {
/* get dt and sysconfig */
rc = sunxi_ir_startup(pdev);
}else{
pr_err("sunxi ir device tree err!
");
return -EBUSY;
}
if( rc < 0)
goto err_allocate_device;
sunxi_rcdev = rc_allocate_device();
if (!sunxi_rcdev) {
rc = -ENOMEM;
pr_err("rc dev allocate fail !
");
goto err_allocate_device;
}
sunxi_rcdev->driver_type = RC_DRIVER_IR_RAW;
sunxi_rcdev->input_name = SUNXI_IR_DEVICE_NAME;
sunxi_rcdev->input_phys = SUNXI_IR_DEVICE_NAME "/input0";
sunxi_rcdev->input_id.bustype = BUS_HOST;
sunxi_rcdev->input_id.vendor = 0x0001;
sunxi_rcdev->input_id.product = 0x0001;
sunxi_rcdev->input_id.version = 0x0100;
sunxi_rcdev->dev.parent = &pdev->dev;
sunxi_rcdev->driver_name = SUNXI_IR_DRIVER_NAME;
input_set_capability(sunxi_rcdev->input_dev, EV_REL, REL_X);
input_set_capability(sunxi_rcdev->input_dev, EV_REL, REL_Y);
input_set_capability(sunxi_rcdev->input_dev, EV_KEY, BTN_LEFT);
input_set_capability(sunxi_rcdev->input_dev, EV_KEY, BTN_MIDDLE);
input_set_capability(sunxi_rcdev->input_dev, EV_KEY, BTN_RIGHT);
//input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
#ifdef CONFIG_IR_RC5
sunxi_rcdev->allowed_protos = (u64)RC_BIT_RC5;
#else
sunxi_rcdev->allowed_protos = (u64)RC_BIT_NEC;
#endif
sunxi_rcdev->map_name = RC_MAP_SUNXI;
init_rc_map_sunxi(ir_data->ir_addr, ir_data->ir_addr_cnt);
rc = rc_register_device(sunxi_rcdev);
if (rc < 0) {
dev_err(&pdev->dev, "failed to register rc device
");
goto err_register_rc_device;
}
sunxi_rcdev->enabled_protocols = sunxi_rcdev->allowed_protos;;
sunxi_rcdev->input_dev->dev.init_name = &ir_dev_name[0];
if (0 != rc) {
pr_err("%s: config ir rx pin err.
", __func__);
goto err_platfrom_device;
}
platform_set_drvdata(pdev, sunxi_rcdev);
ir_data->rcdev = sunxi_rcdev;
if(ir_data->suply){
rc = regulator_set_voltage(ir_data->suply, ir_data->suply_vol, ir_data->suply_vol);
rc |= regulator_enable(ir_data->suply);
}
ir_setup();
if (request_irq(ir_data->irq_num, sunxi_ir_recv_irq, IRQF_DISABLED, "RemoteIR_RX",
sunxi_rcdev)) {
pr_err("%s: request irq fail.
", __func__);
rc = -EBUSY;
goto err_request_irq;
}
/* enable here */
dprintk(DEBUG_INIT, "ir probe end!
");
return 0;
err_request_irq:
platform_set_drvdata(pdev, NULL);
rc_unregister_device(sunxi_rcdev);
sunxi_rcdev = NULL;
ir_clk_uncfg();
if(ir_data->suply){
regulator_disable(ir_data->suply);
regulator_put(ir_data->suply);
}
err_platfrom_device:
exit_rc_map_sunxi();
err_register_rc_device:
rc_free_device(sunxi_rcdev);
err_allocate_device:
if(ir_data)
kfree(ir_data);
return rc;
}
static int sunxi_ir_recv_remove(struct platform_device *pdev)
{
free_irq(ir_data->irq_num, sunxi_rcdev);
ir_clk_uncfg();
platform_set_drvdata(pdev, NULL);
if(ir_data->suply){
regulator_disable(ir_data->suply);
regulator_put(ir_data->suply);
}
rc_unregister_device(sunxi_rcdev);
exit_rc_map_sunxi();
if(ir_data)
kfree(ir_data);
return 0;
}
#ifdef CONFIG_PM
static int sunxi_ir_recv_suspend(struct device *dev)
{
dprintk(DEBUG_SUSPEND, "enter: sunxi_ir_rx_suspend.
");
disable_irq_nosync(ir_data->irq_num);
if(NULL == ir_data->mclk || IS_ERR(ir_data->mclk)) {
pr_err("ir_clk handle is invalid, just return!
");
return -1;
} else {
clk_disable_unprepare(ir_data->mclk);
}
return 0;
}
static int sunxi_ir_recv_resume(struct device *dev)
{
dprintk(DEBUG_SUSPEND, "enter: sunxi_ir_rx_resume.
");
clk_prepare_enable(ir_data->mclk);
ir_reg_cfg();
enable_irq(ir_data->irq_num);
return 0;
}
static const struct dev_pm_ops sunxi_ir_recv_pm_ops = {
.suspend = sunxi_ir_recv_suspend,
.resume = sunxi_ir_recv_resume,
};
#endif
static struct platform_driver sunxi_ir_recv_driver = {
.probe = sunxi_ir_recv_probe,
.remove = sunxi_ir_recv_remove,
.driver = {
.name = SUNXI_IR_DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(sunxi_ir_recv_of_match),
#ifdef CONFIG_PM
.pm = &sunxi_ir_recv_pm_ops,
#endif
},
};
module_platform_driver(sunxi_ir_recv_driver);
module_param_named(debug_mask, debug_mask, int, 0644);
MODULE_DESCRIPTION("SUNXI IR Receiver driver");
MODULE_AUTHOR("QIn");
MODULE_LICENSE("GPL v2");
ir-nec-decoder.c
/* ir-nec-decoder.c - handle NEC IR Pulse/Space protocol * * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com> * * 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 NEC_NBITS 8 #define NEC_UNIT 562500 /* ns */ #define NEC_HEADER_PULSE (16 * NEC_UNIT) #define NECX_HEADER_PULSE (8 * NEC_UNIT) /* Less common NEC variant */ #define NEC_HEADER_SPACE (8 * NEC_UNIT) #define NEC_REPEAT_SPACE (4 * NEC_UNIT) #define NEC_BIT_PULSE (1 * NEC_UNIT) #define NEC_BIT_0_SPACE (1 * NEC_UNIT) #define NEC_BIT_1_SPACE (3 * NEC_UNIT) #define NEC_TRAILER_PULSE (1 * NEC_UNIT) #define NEC_TRAILER_SPACE (10 * NEC_UNIT) /* even longer in reality */ #define NECX_REPEAT_BITS 1 /*********** fsp *************/ #define fsp_head_first 5000000 #define fsp_head_end 5000000 #define data_first 500000 #define data_end_0 1500000 #define data_end_1 500000 #define fsp_end 1000000 /*******************************/ enum nec_state { STATE_INACTIVE, STATE_HEADER_SPACE, STATE_BIT_PULSE, STATE_BIT_SPACE, STATE_TRAILER_PULSE, STATE_TRAILER_SPACE, }; /** * ir_nec_decode() - Decode one NEC 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_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) { struct nec_dec *data = &dev->raw->nec; u32 scancode; u8 address, not_address, command, not_command; bool send_32bits = false; if (!(dev->enabled_protocols & RC_BIT_NEC)) return 0; if (!is_timing_event(ev)) { if (ev.reset) data->state = STATE_INACTIVE; return 0; } IR_dprintk(2, "NEC decode started at state %d (%uus %s) ", data->state, TO_US(ev.duration), TO_STR(ev.pulse)); switch (data->state) { case STATE_INACTIVE: //0 // printk("STATE_INACTIVE=0x%x , time = %d ",STATE_INACTIVE,ev.duration); if (!ev.pulse) break; if (eq_margin(ev.duration, fsp_head_first, NEC_UNIT * 3)) { data->is_nec_x = false; data->necx_repeat = false; } else if (eq_margin(ev.duration, fsp_head_end, NEC_UNIT * 3)) data->is_nec_x = true; else break; data->count = 0; data->state = STATE_HEADER_SPACE; return 0; case STATE_HEADER_SPACE: //1 // printk("STATE_HEADER_SPACE = 0x%x, time = %d ",STATE_HEADER_SPACE,ev.duration); if (ev.pulse) break; if (eq_margin(ev.duration, fsp_head_end, NEC_UNIT * 3)) { data->state = STATE_BIT_PULSE; return 0; } /* else if (eq_margin(ev.duration, NEC_REPEAT_SPACE, NEC_UNIT / 2)) { if (!dev->keypressed) { IR_dprintk(1, "Discarding last key repeat: event after key up "); } else { rc_repeat(dev); IR_dprintk(1, "Repeat last key "); data->state = STATE_TRAILER_PULSE; } return 0; } */ break; case STATE_BIT_PULSE: //2 // printk("STATE_BIT_PULSE = 0x%x, time = %d ",STATE_BIT_PULSE,ev.duration); if (!ev.pulse) break; if (eq_margin(ev.duration, data_first, NEC_UNIT * 2)) // 500 break; data->state = STATE_BIT_SPACE; return 0; case STATE_BIT_SPACE: //3 // printk("STATE_BIT_SPACE = 0x%x, time = %d ",STATE_BIT_SPACE,ev.duration); if (ev.pulse) break; if (data->necx_repeat && data->count == NECX_REPEAT_BITS && geq_margin(ev.duration, 1000, NEC_UNIT / 2)) { IR_dprintk(1, "Repeat last key "); rc_repeat(dev); data->state = STATE_INACTIVE; return 0; } else if (data->count > NECX_REPEAT_BITS) data->necx_repeat = false; data->bits <<= 1; if (eq_margin(ev.duration, data_end_1, 300000)) data->bits |= 1; else if (!eq_margin(ev.duration, data_end_0, 300000)) data->bits |= 0; data->count++; if (data->count == NEC_NBITS) //32bit data->state = STATE_TRAILER_PULSE; else data->state = STATE_BIT_PULSE; return 0; case STATE_TRAILER_PULSE: //4 // printk("SSTATE_TRAILER_PULSE = 0x%x, time = %d ",STATE_TRAILER_PULSE,ev.duration); if (!ev.pulse) break; if (!eq_margin(ev.duration, fsp_end, 100000)) break; data->state = STATE_TRAILER_SPACE; return 0; case STATE_TRAILER_SPACE: //5 // printk("STATE_TRAILER_SPACE = 0x%x, time = %d ",STATE_TRAILER_SPACE,ev.duration); if (ev.pulse) break; //if (!geq_margin(ev.duration, NEC_TRAILER_SPACE, NEC_UNIT / 2)) // break; #if 0 address = (data->bits & 0xff000000) >> 24; not_address = (data->bits & 0xff0000) >> 16; command = (data->bits & 0xff00) >> 8; not_command = (data->bits & 0xff) >> 0; if((address ^ not_address) == 0xff){ if((command ^ not_command) == 0xff){ scancode = (address << 8)| command; } else{ data->state = STATE_INACTIVE; return 0; } } else{ data->state = STATE_INACTIVE; return 0; } #endif address = data->bits & 0x0f; command = (data->bits & 0xf0)>>4; if((address ^ command) == 0x0f) scancode = data->bits &0xff; else data->state = STATE_INACTIVE; printk(" _______________NEC scancode_______________ = 0x%x ",scancode); #if 0 address = bitrev8((data->bits >> 24) & 0xff); not_address = bitrev8((data->bits >> 16) & 0xff); command = bitrev8((data->bits >> 8) & 0xff); not_command = bitrev8((data->bits >> 0) & 0xff); if ((command ^ not_command) != 0xff) { IR_dprintk(1, "NEC checksum error: received 0x%08x ", data->bits); send_32bits = true; } if (send_32bits) { /* NEC transport, but modified protocol, used by at * least Apple and TiVo remotes */ scancode = data->bits; IR_dprintk(1, "NEC (modified) scancode 0x%08x ", scancode); } else if ((address ^ not_address) != 0xff) { /* Extended NEC */ scancode = address << 16 | not_address << 8 | command; IR_dprintk(1, "NEC (Ext) scancode 0x%06x ", scancode); } else { /* Normal NEC */ scancode = address << 8 | command; IR_dprintk(1, "NEC scancode 0x%04x ", scancode); } if (data->is_nec_x) data->necx_repeat = true; #endif rc_keydown(dev, scancode, 0); data->state = STATE_INACTIVE; scancode = 0; return 0; } IR_dprintk(1, "NEC decode failed at count %d state %d (%uus %s) ", data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse)); data->state = STATE_INACTIVE; return -EINVAL; } static struct ir_raw_handler nec_handler = { .protocols = RC_BIT_NEC, .decode = ir_nec_decode, }; static int __init ir_nec_decode_init(void) { ir_raw_handler_register(&nec_handler); printk(KERN_INFO "IR NEC protocol handler initialized "); return 0; } static void __exit ir_nec_decode_exit(void) { ir_raw_handler_unregister(&nec_handler); } module_init(ir_nec_decode_init); module_exit(ir_nec_decode_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); MODULE_DESCRIPTION("NEC IR protocol decoder");
rc-sunxi-keymaps.c
/* Sunxi Remote Controller * * keymap imported from ir-keymaps.c * * Copyright (c) 2014 by allwinnertech * * 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; either version 2 of the License, or * (at your option) any later version. */ #include <media/rc-map.h> #include "sunxi-ir-rx.h" #define MAX_ADDR_NUM (18) static u32 match_addr[MAX_ADDR_NUM]; static u32 match_num; static struct rc_map_table sunxi_nec_scan[] = { // { KEY_ESC, KEY_ESC }, #if 0 { 0x0812, KEY_VOLUMEDOWN }, { 0x0813, KEY_VOLUMEUP }, { 0x0850, KEY_PLAY }, /*********** FSP begin KEYCODE_MEDIA_PLAY *********/ { 0x0851, KEY_PAUSE }, { 0x0852, KEY_BACK }, { 0x0853, KEY_FORWARD }, { 0x0854, KEY_CLOSECD }, { 0x0855, KEY_EJECTCD }, { 0x0856, KEY_EJECTCLOSECD }, { 0x0857, KEY_NEXTSONG }, { 0x0858, KEY_PLAYPAUSE }, { 0x0859, KEY_PREVIOUSSONG }, { 0x0860, KEY_STOPCD }, { 0x0861, KEY_RECORD }, { 0x0862, KEY_REWIND }, { 0x0863, KEY_FASTFORWARD}, { 0x0864, KEY_STOP}, #endif { 0xE1, KEY_VOLUMEDOWN }, { 0x1E, KEY_VOLUMEUP }, { 0xD2, KEY_PLAY }, /*********** FSP begin KEYCODE_MEDIA_PLAY *********/ { 0x2D, KEY_PAUSE }, { 0xC3, KEY_BACK }, { 0x3C, KEY_FORWARD }, { 0xB4, KEY_CLOSECD }, { 0x4B, KEY_EJECTCD }, { 0xA5, KEY_EJECTCLOSECD }, { 0x5A, KEY_NEXTSONG }, { 0xF0, KEY_PLAYPAUSE }, { 0x0F, KEY_PREVIOUSSONG }, { 0x96, KEY_STOPCD }, // { 0x69, KEY_RECORD }, { 0x87, KEY_REWIND }, { 0x78, KEY_FASTFORWARD}, { 0x69, KEY_STOP}, }; static u32 sunxi_key_mapping(u32 code) { u32 i,temp; temp = (code >> 8)&0xffff; for(i = 0; i < match_num; i++){ if(match_addr[i] == temp) return code; } return KEY_RESERVED; } static struct rc_map_list sunxi_map = { .map = { .scan = sunxi_nec_scan, .size = ARRAY_SIZE(sunxi_nec_scan), // .mapping = sunxi_key_mapping, .rc_type = RC_TYPE_NEC, /* Legacy IR type */ .name = RC_MAP_SUNXI, } }; static void init_addr(u32 *addr, u32 addr_num) { u32 *temp_addr = match_addr; if(addr_num > MAX_ADDR_NUM) addr_num = MAX_ADDR_NUM; match_num = addr_num; while(addr_num--){ *temp_addr++ = (*addr++)&0xffff; } return; } int init_rc_map_sunxi(u32 *addr, u32 addr_num) { init_addr(addr,addr_num); return rc_map_register(&sunxi_map); } void exit_rc_map_sunxi(void) { rc_map_unregister(&sunxi_map); }
rc-main.c
/* rc-main.c - Remote Controller core module * * Copyright (C) 2009-2010 by Mauro Carvalho Chehab <mchehab@redhat.com> * * 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 <media/rc-core.h> #include <linux/spinlock.h> #include <linux/delay.h> #include <linux/input.h> #include <linux/slab.h> #include <linux/device.h> #include <linux/module.h> #include "rc-core-priv.h" /* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */ #define IR_TAB_MIN_SIZE 256 #define IR_TAB_MAX_SIZE 8192 /* FIXME: IR_KEYPRESS_TIMEOUT should be protocol specific */ #define IR_KEYPRESS_TIMEOUT 250 /* Used to keep track of known keymaps */ static LIST_HEAD(rc_map_list); static DEFINE_SPINLOCK(rc_map_lock); static struct rc_map_list *seek_rc_map(const char *name) { struct rc_map_list *map = NULL; spin_lock(&rc_map_lock); list_for_each_entry(map, &rc_map_list, list) { if (!strcmp(name, map->map.name)) { spin_unlock(&rc_map_lock); return map; } } spin_unlock(&rc_map_lock); return NULL; } struct rc_map *rc_map_get(const char *name) { struct rc_map_list *map; map = seek_rc_map(name); #ifdef MODULE if (!map) { int rc = request_module(name); if (rc < 0) { printk(KERN_ERR "Couldn't load IR keymap %s ", name); return NULL; } msleep(20); /* Give some time for IR to register */ map = seek_rc_map(name); } #endif if (!map) { printk(KERN_ERR "IR keymap %s not found ", name); return NULL; } printk(KERN_INFO "Registered IR keymap %s ", map->map.name); return &map->map; } EXPORT_SYMBOL_GPL(rc_map_get); int rc_map_register(struct rc_map_list *map) { spin_lock(&rc_map_lock); list_add_tail(&map->list, &rc_map_list); spin_unlock(&rc_map_lock); return 0; } EXPORT_SYMBOL_GPL(rc_map_register); void rc_map_unregister(struct rc_map_list *map) { spin_lock(&rc_map_lock); list_del(&map->list); spin_unlock(&rc_map_lock); } EXPORT_SYMBOL_GPL(rc_map_unregister); static struct rc_map_table empty[] = { { 0x2a, KEY_COFFEE }, }; static struct rc_map_list empty_map = { .map = { .scan = empty, .size = ARRAY_SIZE(empty), .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ .name = RC_MAP_EMPTY, } }; /** * ir_create_table() - initializes a scancode table * @rc_map: the rc_map to initialize * @name: name to assign to the table * @rc_type: ir type to assign to the new table * @size: initial size of the table * @return: zero on success or a negative error code * * This routine will initialize the rc_map and will allocate * memory to hold at least the specified number of elements. */ static int ir_create_table(struct rc_map *rc_map, const char *name, u64 rc_type, size_t size) { rc_map->name = name; rc_map->rc_type = rc_type; rc_map->alloc = roundup_pow_of_two(size * sizeof(struct rc_map_table)); rc_map->size = rc_map->alloc / sizeof(struct rc_map_table); rc_map->scan = kmalloc(rc_map->alloc, GFP_KERNEL); if (!rc_map->scan) return -ENOMEM; IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes) ", rc_map->size, rc_map->alloc); return 0; } /** * ir_free_table() - frees memory allocated by a scancode table * @rc_map: the table whose mappings need to be freed * * This routine will free memory alloctaed for key mappings used by given * scancode table. */ static void ir_free_table(struct rc_map *rc_map) { rc_map->size = 0; if(rc_map->scan){ kfree(rc_map->scan); rc_map->scan = NULL; } } /** * ir_resize_table() - resizes a scancode table if necessary * @rc_map: the rc_map to resize * @gfp_flags: gfp flags to use when allocating memory * @return: zero on success or a negative error code * * This routine will shrink the rc_map if it has lots of * unused entries and grow it if it is full. */ static int ir_resize_table(struct rc_map *rc_map, gfp_t gfp_flags) { unsigned int oldalloc = rc_map->alloc; unsigned int newalloc = oldalloc; struct rc_map_table *oldscan = rc_map->scan; struct rc_map_table *newscan; if (rc_map->size == rc_map->len) { /* All entries in use -> grow keytable */ if (rc_map->alloc >= IR_TAB_MAX_SIZE) return -ENOMEM; newalloc *= 2; IR_dprintk(1, "Growing table to %u bytes ", newalloc); } if ((rc_map->len * 3 < rc_map->size) && (oldalloc > IR_TAB_MIN_SIZE)) { /* Less than 1/3 of entries in use -> shrink keytable */ newalloc /= 2; IR_dprintk(1, "Shrinking table to %u bytes ", newalloc); } if (newalloc == oldalloc) return 0; newscan = kmalloc(newalloc, gfp_flags); if (!newscan) { IR_dprintk(1, "Failed to kmalloc %u bytes ", newalloc); return -ENOMEM; } memcpy(newscan, rc_map->scan, rc_map->len * sizeof(struct rc_map_table)); rc_map->scan = newscan; rc_map->alloc = newalloc; rc_map->size = rc_map->alloc / sizeof(struct rc_map_table); kfree(oldscan); return 0; } /** * ir_update_mapping() - set a keycode in the scancode->keycode table * @dev: the struct rc_dev device descriptor * @rc_map: scancode table to be adjusted * @index: index of the mapping that needs to be updated * @keycode: the desired keycode * @return: previous keycode assigned to the mapping * * This routine is used to update scancode->keycode mapping at given * position. */ static unsigned int ir_update_mapping(struct rc_dev *dev, struct rc_map *rc_map, unsigned int index, unsigned int new_keycode) { int old_keycode = rc_map->scan[index].keycode; int i; /* Did the user wish to remove the mapping? */ if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) { IR_dprintk(1, "#%d: Deleting scan 0x%04x ", index, rc_map->scan[index].scancode); rc_map->len--; memmove(&rc_map->scan[index], &rc_map->scan[index+ 1], (rc_map->len - index) * sizeof(struct rc_map_table)); } else { IR_dprintk(1, "#%d: %s scan 0x%04x with key 0x%04x ", index, old_keycode == KEY_RESERVED ? "New" : "Replacing", rc_map->scan[index].scancode, new_keycode); rc_map->scan[index].keycode = new_keycode; __set_bit(new_keycode, dev->input_dev->keybit); } if (old_keycode != KEY_RESERVED) { /* A previous mapping was updated... */ __clear_bit(old_keycode, dev->input_dev->keybit); /* ... but another scancode might use the same keycode */ for (i = 0; i < rc_map->len; i++) { if (rc_map->scan[i].keycode == old_keycode) { __set_bit(old_keycode, dev->input_dev->keybit); break; } } /* Possibly shrink the keytable, failure is not a problem */ ir_resize_table(rc_map, GFP_ATOMIC); } return old_keycode; } /** * ir_establish_scancode() - set a keycode in the scancode->keycode table * @dev: the struct rc_dev device descriptor * @rc_map: scancode table to be searched * @scancode: the desired scancode * @resize: controls whether we allowed to resize the table to * accommodate not yet present scancodes * @return: index of the mapping containing scancode in question * or -1U in case of failure. * * This routine is used to locate given scancode in rc_map. * If scancode is not yet present the routine will allocate a new slot * for it. */ static unsigned int ir_establish_scancode(struct rc_dev *dev, struct rc_map *rc_map, unsigned int scancode, bool resize) { unsigned int i; /* * Unfortunately, some hardware-based IR decoders don't provide * all bits for the complete IR code. In general, they provide only * the command part of the IR code. Yet, as it is possible to replace * the provided IR with another one, it is needed to allow loading * IR tables from other remotes. So, we support specifying a mask to * indicate the valid bits of the scancodes. */ if (dev->scanmask) scancode &= dev->scanmask; /* First check if we already have a mapping for this ir command */ for (i = 0; i < rc_map->len; i++) { if (rc_map->scan[i].scancode == scancode) return i; /* Keytable is sorted from lowest to highest scancode */ if (rc_map->scan[i].scancode >= scancode) break; } /* No previous mapping found, we might need to grow the table */ if (rc_map->size == rc_map->len) { if (!resize || ir_resize_table(rc_map, GFP_ATOMIC)) return -1U; } /* i is the proper index to insert our new keycode */ if (i < rc_map->len) memmove(&rc_map->scan[i + 1], &rc_map->scan[i], (rc_map->len - i) * sizeof(struct rc_map_table)); rc_map->scan[i].scancode = scancode; rc_map->scan[i].keycode = KEY_RESERVED; rc_map->len++; return i; } /** * ir_setkeycode() - set a keycode in the scancode->keycode table * @idev: the struct input_dev device descriptor * @scancode: the desired scancode * @keycode: result * @return: -EINVAL if the keycode could not be inserted, otherwise zero. * * This routine is used to handle evdev EVIOCSKEY ioctl. */ static int ir_setkeycode(struct input_dev *idev, const struct input_keymap_entry *ke, unsigned int *old_keycode) { struct rc_dev *rdev = input_get_drvdata(idev); struct rc_map *rc_map = &rdev->rc_map; unsigned int index; unsigned int scancode; int retval = 0; unsigned long flags; spin_lock_irqsave(&rc_map->lock, flags); if (ke->flags & INPUT_KEYMAP_BY_INDEX) { index = ke->index; if (index >= rc_map->len) { retval = -EINVAL; goto out; } } else { retval = input_scancode_to_scalar(ke, &scancode); if (retval) goto out; index = ir_establish_scancode(rdev, rc_map, scancode, true); if (index >= rc_map->len) { retval = -ENOMEM; goto out; } } *old_keycode = ir_update_mapping(rdev, rc_map, index, ke->keycode); out: spin_unlock_irqrestore(&rc_map->lock, flags); return retval; } /** * ir_setkeytable() - sets several entries in the scancode->keycode table * @dev: the struct rc_dev device descriptor * @to: the struct rc_map to copy entries to * @from: the struct rc_map to copy entries from * @return: -ENOMEM if all keycodes could not be inserted, otherwise zero. * * This routine is used to handle table initialization. */ static int ir_setkeytable(struct rc_dev *dev, const struct rc_map *from) { struct rc_map *rc_map = &dev->rc_map; unsigned int i, index; int rc; rc = ir_create_table(rc_map, from->name, from->rc_type, from->size); if (rc) return rc; IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes) ", rc_map->size, rc_map->alloc); for (i = 0; i < from->size; i++) { index = ir_establish_scancode(dev, rc_map, from->scan[i].scancode, false); if (index >= rc_map->len) { rc = -ENOMEM; break; } ir_update_mapping(dev, rc_map, index, from->scan[i].keycode); } if (rc) ir_free_table(rc_map); return rc; } static int ir_setkeytable_mapping(struct rc_dev *dev, const struct rc_map *from) { struct rc_map *rc_map = &dev->rc_map; if(from->mapping) rc_map->mapping = from->mapping;; return 0; } /** * ir_lookup_by_scancode() - locate mapping by scancode * @rc_map: the struct rc_map to search * @scancode: scancode to look for in the table * @return: index in the table, -1U if not found * * This routine performs binary search in RC keykeymap table for * given scancode. */ static unsigned int ir_lookup_by_scancode(const struct rc_map *rc_map, unsigned int scancode) { int start = 0; int end = rc_map->len - 1; int mid; while (start <= end) { mid = (start + end) / 2; if (rc_map->scan[mid].scancode < scancode) start = mid + 1; else if (rc_map->scan[mid].scancode > scancode) end = mid - 1; else return mid; } return -1U; } /** * ir_getkeycode() - get a keycode from the scancode->keycode table * @idev: the struct input_dev device descriptor * @scancode: the desired scancode * @keycode: used to return the keycode, if found, or KEY_RESERVED * @return: always returns zero. * * This routine is used to handle evdev EVIOCGKEY ioctl. */ static int ir_getkeycode(struct input_dev *idev, struct input_keymap_entry *ke) { struct rc_dev *rdev = input_get_drvdata(idev); struct rc_map *rc_map = &rdev->rc_map; struct rc_map_table *entry; unsigned long flags; unsigned int index; unsigned int scancode; int retval; spin_lock_irqsave(&rc_map->lock, flags); if (ke->flags & INPUT_KEYMAP_BY_INDEX) { index = ke->index; } else { retval = input_scancode_to_scalar(ke, &scancode); if (retval) goto out; index = ir_lookup_by_scancode(rc_map, scancode); } if (index < rc_map->len) { entry = &rc_map->scan[index]; ke->index = index; ke->keycode = entry->keycode; ke->len = sizeof(entry->scancode); memcpy(ke->scancode, &entry->scancode, sizeof(entry->scancode)); } else if (!(ke->flags & INPUT_KEYMAP_BY_INDEX)) { /* * We do not really know the valid range of scancodes * so let's respond with KEY_RESERVED to anything we * do not have mapping for [yet]. */ ke->index = index; ke->keycode = KEY_RESERVED; } else { retval = -EINVAL; goto out; } retval = 0; out: spin_unlock_irqrestore(&rc_map->lock, flags); return retval; } /** * rc_g_keycode_from_table() - gets the keycode that corresponds to a scancode * @dev: the struct rc_dev descriptor of the device * @scancode: the scancode to look for * @return: the corresponding keycode, or KEY_RESERVED * * This routine is used by drivers which need to convert a scancode to a * keycode. Normally it should not be used since drivers should have no * interest in keycodes. */ u32 rc_g_keycode_from_table(struct rc_dev *dev, u32 scancode) { struct rc_map *rc_map = &dev->rc_map; unsigned int keycode; unsigned int index; unsigned long flags; spin_lock_irqsave(&rc_map->lock, flags); if(rc_map->mapping){ keycode = rc_map->mapping(scancode); }else{ index = ir_lookup_by_scancode(rc_map, scancode); keycode = index < rc_map->len ? rc_map->scan[index].keycode : KEY_RESERVED; } spin_unlock_irqrestore(&rc_map->lock, flags); if (keycode != KEY_RESERVED) IR_dprintk(1, "%s: scancode 0x%04x keycode 0x%02x ", dev->input_name, scancode, keycode); return keycode; } EXPORT_SYMBOL_GPL(rc_g_keycode_from_table); /** * ir_do_keyup() - internal function to signal the release of a keypress * @dev: the struct rc_dev descriptor of the device * @sync: whether or not to call input_sync * * This function is used internally to release a keypress, it must be * called with keylock held. */ static void ir_do_keyup(struct rc_dev *dev, bool sync) { if (!dev->keypressed) return; IR_dprintk(1, "keyup key 0x%04x ", dev->last_keycode); input_report_key(dev->input_dev, dev->last_keycode, 0); if (sync) input_sync(dev->input_dev); dev->keypressed = false; } /** * rc_keyup() - signals the release of a keypress * @dev: the struct rc_dev descriptor of the device * * This routine is used to signal that a key has been released on the * remote control. */ void rc_keyup(struct rc_dev *dev) { unsigned long flags; spin_lock_irqsave(&dev->keylock, flags); ir_do_keyup(dev, true); spin_unlock_irqrestore(&dev->keylock, flags); } EXPORT_SYMBOL_GPL(rc_keyup); /** * ir_timer_keyup() - generates a keyup event after a timeout * @cookie: a pointer to the struct rc_dev for the device * * This routine will generate a keyup event some time after a keydown event * is generated when no further activity has been detected. */ static void ir_timer_keyup(unsigned long cookie) { struct rc_dev *dev = (struct rc_dev *)cookie; unsigned long flags; /* * ir->keyup_jiffies is used to prevent a race condition if a * hardware interrupt occurs at this point and the keyup timer * event is moved further into the future as a result. * * The timer will then be reactivated and this function called * again in the future. We need to exit gracefully in that case * to allow the input subsystem to do its auto-repeat magic or * a keyup event might follow immediately after the keydown. */ spin_lock_irqsave(&dev->keylock, flags); if (time_is_before_eq_jiffies(dev->keyup_jiffies)) ir_do_keyup(dev, true); spin_unlock_irqrestore(&dev->keylock, flags); } /** * rc_repeat() - signals that a key is still pressed * @dev: the struct rc_dev descriptor of the device * * This routine is used by IR decoders when a repeat message which does * not include the necessary bits to reproduce the scancode has been * received. */ void rc_repeat(struct rc_dev *dev) { unsigned long flags; spin_lock_irqsave(&dev->keylock, flags); // input_event(dev->input_dev, EV_ABS, ABS_X, dev->last_scancode); input_event(dev->input_dev, EV_MSC, MSC_SCAN, dev->last_scancode); // input_event(dev->input_dev, EV_REL, REL_X, dev->last_scancode); input_sync(dev->input_dev); if (!dev->keypressed) goto out; dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT); mod_timer(&dev->timer_keyup, dev->keyup_jiffies); out: spin_unlock_irqrestore(&dev->keylock, flags); } EXPORT_SYMBOL_GPL(rc_repeat); /** * ir_do_keydown() - internal function to process a keypress * @dev: the struct rc_dev descriptor of the device * @scancode: the scancode of the keypress * @keycode: the keycode of the keypress * @toggle: the toggle value of the keypress * * This function is used internally to register a keypress, it must be * called with keylock held. */ static void ir_do_keydown(struct rc_dev *dev, int scancode, u32 keycode, u8 toggle) { bool new_event = !dev->keypressed || dev->last_scancode != scancode || dev->last_toggle != toggle; if (new_event && dev->keypressed) ir_do_keyup(dev, false); /* switch(scancode){ send_user_event(""KEYCODE_BREAK=128""); case 0xD2: input_event(dev->input_dev, EV_KEY, KEY_PLAY, scancode); break; case 0x2D: input_event(dev->input_dev, EV_KEY, KEY_PAUSE, scancode); break; default: break; } */ input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode); input_event(dev->input_dev, EV_REL, REL_X, scancode); // input_event(dev->input_dev, EV_ABS, ABS_X, scancode); if (new_event && keycode != KEY_RESERVED) { /* Register a keypress */ dev->keypressed = true; dev->last_scancode = scancode; dev->last_toggle = toggle; dev->last_keycode = keycode; IR_dprintk(1, "%s: key down event, " "key 0x%04x, scancode 0x%04x ", dev->input_name, keycode, scancode); input_report_key(dev->input_dev, keycode, 1); input_report_rel(dev->input_dev, REL_X, scancode); } // input_report_rel(dev->input_dev, REL_X, scancode); input_sync(dev->input_dev); } /** * rc_keydown() - generates input event for a key press * @dev: the struct rc_dev descriptor of the device * @scancode: the scancode that we're seeking * @toggle: the toggle value (protocol dependent, if the protocol doesn't * support toggle values, this should be set to zero) * * This routine is used to signal that a key has been pressed on the * remote control. */ void rc_keydown(struct rc_dev *dev, int scancode, u8 toggle) { unsigned long flags; u32 keycode = rc_g_keycode_from_table(dev, scancode); spin_lock_irqsave(&dev->keylock, flags); ir_do_keydown(dev, scancode, keycode, toggle); // __set_bit(ABS_X, gt811_dev->inputdev->absbit); /* input_event(dev->input_dev, EV_REL, REL_X, scancode); input_report_rel(dev->input_dev, REL_X, scancode); input_sync(dev->input_dev); */ /* input_event(dev->input_dev, EV_ABS, ABS_X, scancode); input_report_rel(dev->input_dev, ABS_X, scancode); input_sync(dev->input_dev); */ printk("rc_keydown success ! "); if (dev->keypressed) { dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT); mod_timer(&dev->timer_keyup, dev->keyup_jiffies); } spin_unlock_irqrestore(&dev->keylock, flags); } EXPORT_SYMBOL_GPL(rc_keydown); /** * rc_keydown_notimeout() - generates input event for a key press without * an automatic keyup event at a later time * @dev: the struct rc_dev descriptor of the device * @scancode: the scancode that we're seeking * @toggle: the toggle value (protocol dependent, if the protocol doesn't * support toggle values, this should be set to zero) * * This routine is used to signal that a key has been pressed on the * remote control. The driver must manually call rc_keyup() at a later stage. */ void rc_keydown_notimeout(struct rc_dev *dev, int scancode, u8 toggle) { unsigned long flags; u32 keycode = rc_g_keycode_from_table(dev, scancode); spin_lock_irqsave(&dev->keylock, flags); ir_do_keydown(dev, scancode, keycode, toggle); spin_unlock_irqrestore(&dev->keylock, flags); } EXPORT_SYMBOL_GPL(rc_keydown_notimeout); static int ir_open(struct input_dev *idev) { struct rc_dev *rdev = input_get_drvdata(idev); return rdev->open(rdev); } static void ir_close(struct input_dev *idev) { struct rc_dev *rdev = input_get_drvdata(idev); if (rdev) rdev->close(rdev); } /* class for /sys/class/rc */ static char *rc_devnode(struct device *dev, umode_t *mode) { return kasprintf(GFP_KERNEL, "rc/%s", dev_name(dev)); } static struct class rc_class = { .name = "rc", .devnode = rc_devnode, }; /* * These are the protocol textual descriptions that are * used by the sysfs protocols file. Note that the order * of the entries is relevant. */ static struct { u64 type; char *name; } proto_names[] = { { RC_BIT_NONE, "none" }, { RC_BIT_OTHER, "other" }, { RC_BIT_UNKNOWN, "unknown" }, { RC_BIT_RC5 | RC_BIT_RC5X, "rc-5" }, { RC_BIT_NEC, "nec" }, { RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE, "rc-6" }, { RC_BIT_JVC, "jvc" }, { RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20, "sony" }, { RC_BIT_RC5_SZ, "rc-5-sz" }, { RC_BIT_SANYO, "sanyo" }, { RC_BIT_MCE_KBD, "mce_kbd" }, { RC_BIT_LIRC, "lirc" }, }; /** * show_protocols() - shows the current IR protocol(s) * @device: the device descriptor * @mattr: the device attribute struct (unused) * @buf: a pointer to the output buffer * * This routine is a callback routine for input read the IR protocol type(s). * it is trigged by reading /sys/class/rc/rc?/protocols. * It returns the protocol names of supported protocols. * Enabled protocols are printed in brackets. * * dev->lock is taken to guard against races between device * registration, store_protocols and show_protocols. */ static ssize_t show_protocols(struct device *device, struct device_attribute *mattr, char *buf) { struct rc_dev *dev = to_rc_dev(device); u64 allowed, enabled; char *tmp = buf; int i; /* Device is being removed */ if (!dev) return -EINVAL; mutex_lock(&dev->lock); enabled = dev->enabled_protocols; if (dev->driver_type == RC_DRIVER_SCANCODE) allowed = dev->allowed_protos; else if (dev->raw) allowed = ir_raw_get_allowed_protocols(); else { mutex_unlock(&dev->lock); return -ENODEV; } IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx ", (long long)allowed, (long long)enabled); for (i = 0; i < ARRAY_SIZE(proto_names); i++) { if (allowed & enabled & proto_names[i].type) tmp += sprintf(tmp, "[%s] ", proto_names[i].name); else if (allowed & proto_names[i].type) tmp += sprintf(tmp, "%s ", proto_names[i].name); if (allowed & proto_names[i].type) allowed &= ~proto_names[i].type; } if (tmp != buf) tmp--; *tmp = ' '; mutex_unlock(&dev->lock); return tmp + 1 - buf; } /** * store_protocols() - changes the current IR protocol(s) * @device: the device descriptor * @mattr: the device attribute struct (unused) * @buf: a pointer to the input buffer * @len: length of the input buffer * * This routine is for changing the IR protocol type. * It is trigged by writing to /sys/class/rc/rc?/protocols. * Writing "+proto" will add a protocol to the list of enabled protocols. * Writing "-proto" will remove a protocol from the list of enabled protocols. * Writing "proto" will enable only "proto". * Writing "none" will disable all protocols. * Returns -EINVAL if an invalid protocol combination or unknown protocol name * is used, otherwise @len. * * dev->lock is taken to guard against races between device * registration, store_protocols and show_protocols. */ static ssize_t store_protocols(struct device *device, struct device_attribute *mattr, const char *data, size_t len) { struct rc_dev *dev = to_rc_dev(device); bool enable, disable; const char *tmp; u64 type; u64 mask; int rc, i, count = 0; ssize_t ret; /* Device is being removed */ if (!dev) return -EINVAL; mutex_lock(&dev->lock); if (dev->driver_type != RC_DRIVER_SCANCODE && !dev->raw) { IR_dprintk(1, "Protocol switching not supported "); ret = -EINVAL; goto out; } type = dev->enabled_protocols; while ((tmp = strsep((char **) &data, " ")) != NULL) { if (!*tmp) break; if (*tmp == '+') { enable = true; disable = false; tmp++; } else if (*tmp == '-') { enable = false; disable = true; tmp++; } else { enable = false; disable = false; } for (i = 0; i < ARRAY_SIZE(proto_names); i++) { if (!strcasecmp(tmp, proto_names[i].name)) { mask = proto_names[i].type; break; } } if (i == ARRAY_SIZE(proto_names)) { IR_dprintk(1, "Unknown protocol: '%s' ", tmp); ret = -EINVAL; goto out; } count++; if (enable) type |= mask; else if (disable) type &= ~mask; else type = mask; } if (!count) { IR_dprintk(1, "Protocol not specified "); ret = -EINVAL; goto out; } if (dev->change_protocol) { rc = dev->change_protocol(dev, &type); if (rc < 0) { IR_dprintk(1, "Error setting protocols to 0x%llx ", (long long)type); ret = -EINVAL; goto out; } } dev->enabled_protocols = type; IR_dprintk(1, "Current protocol(s): 0x%llx ", (long long)type); ret = len; out: mutex_unlock(&dev->lock); return ret; } static void rc_dev_release(struct device *device) { } #define ADD_HOTPLUG_VAR(fmt, val...) do { int err = add_uevent_var(env, fmt, val); if (err) return err; } while (0) static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env) { struct rc_dev *dev = to_rc_dev(device); if (!dev || !dev->input_dev) return -ENODEV; if (dev->rc_map.name) ADD_HOTPLUG_VAR("NAME=%s", dev->rc_map.name); if (dev->driver_name) ADD_HOTPLUG_VAR("DRV_NAME=%s", dev->driver_name); return 0; } /* * Static device attribute struct with the sysfs attributes for IR's */ static DEVICE_ATTR(protocols, S_IRUGO | S_IWUSR, show_protocols, store_protocols); static struct attribute *rc_dev_attrs[] = { &dev_attr_protocols.attr, NULL, }; static struct attribute_group rc_dev_attr_grp = { .attrs = rc_dev_attrs, }; static const struct attribute_group *rc_dev_attr_groups[] = { &rc_dev_attr_grp, NULL }; static struct device_type rc_dev_type = { .groups = rc_dev_attr_groups, .release = rc_dev_release, .uevent = rc_dev_uevent, }; struct rc_dev *rc_allocate_device(void) { struct rc_dev *dev; dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return NULL; dev->input_dev = input_allocate_device(); if (!dev->input_dev) { kfree(dev); return NULL; } dev->input_dev->getkeycode = ir_getkeycode; dev->input_dev->setkeycode = ir_setkeycode; input_set_drvdata(dev->input_dev, dev); spin_lock_init(&dev->rc_map.lock); spin_lock_init(&dev->keylock); mutex_init(&dev->lock); setup_timer(&dev->timer_keyup, ir_timer_keyup, (unsigned long)dev); dev->dev.type = &rc_dev_type; dev->dev.class = &rc_class; device_initialize(&dev->dev); __module_get(THIS_MODULE); return dev; } EXPORT_SYMBOL_GPL(rc_allocate_device); void rc_free_device(struct rc_dev *dev) { if (!dev) return; if (dev->input_dev) input_free_device(dev->input_dev); put_device(&dev->dev); kfree(dev); module_put(THIS_MODULE); } EXPORT_SYMBOL_GPL(rc_free_device); int rc_register_device(struct rc_dev *dev) { static bool raw_init = false; /* raw decoders loaded? */ static atomic_t devno = ATOMIC_INIT(0); struct rc_map *rc_map; const char *path; int rc; if (!dev || !dev->map_name) return -EINVAL; rc_map = rc_map_get(dev->map_name); if (!rc_map) rc_map = rc_map_get(RC_MAP_EMPTY); if (!rc_map) return -EINVAL; if ((!rc_map->mapping) && (!rc_map->scan || rc_map->size == 0)) return -EINVAL; set_bit(EV_KEY, dev->input_dev->evbit); set_bit(EV_REP, dev->input_dev->evbit); set_bit(EV_MSC, dev->input_dev->evbit); set_bit(MSC_SCAN, dev->input_dev->mscbit); // set_bit(EV_REL, dev->input_dev->evbit); // set_bit(EV_ABS, dev->input_dev->absbit); // set_bit(EV_REL, dev->input_dev->relbit); // __set_bit(EV_REL, dev->input_dev->relbit); if (dev->open) dev->input_dev->open = ir_open; if (dev->close) dev->input_dev->close = ir_close; /* * Take the lock here, as the device sysfs node will appear * when device_add() is called, which may trigger an ir-keytable udev * rule, which will in turn call show_protocols and access * dev->enabled_protocols before it has been initialized. */ mutex_lock(&dev->lock); dev->devno = (unsigned long)(atomic_inc_return(&devno) - 1); dev_set_name(&dev->dev, "rc%ld", dev->devno); dev_set_drvdata(&dev->dev, dev); rc = device_add(&dev->dev); if (rc) goto out_unlock; ir_setkeytable_mapping(dev, rc_map); rc = ir_setkeytable(dev, rc_map); if (rc) goto out_dev; dev->input_dev->dev.parent = &dev->dev; memcpy(&dev->input_dev->id, &dev->input_id, sizeof(dev->input_id)); dev->input_dev->phys = dev->input_phys; dev->input_dev->name = dev->input_name; rc = input_register_device(dev->input_dev); if (rc) goto out_table; /* * Default delay of 250ms is too short for some protocols, especially * since the timeout is currently set to 250ms. Increase it to 500ms, * to avoid wrong repetition of the keycodes. Note that this must be * set after the call to input_register_device(). */ dev->input_dev->rep[REP_DELAY] = 500; /* * As a repeat event on protocols like RC-5 and NEC take as long as * 110/114ms, using 33ms as a repeat period is not the right thing * to do. */ dev->input_dev->rep[REP_PERIOD] = 125; path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); printk(KERN_INFO "%s: %s as %s ", dev_name(&dev->dev), dev->input_name ? dev->input_name : "Unspecified device", path ? path : "N/A"); kfree(path); if (dev->driver_type == RC_DRIVER_IR_RAW) { /* Load raw decoders, if they aren't already */ if (!raw_init) { IR_dprintk(1, "Loading raw decoders "); ir_raw_init(); raw_init = true; } rc = ir_raw_event_register(dev); if (rc < 0) goto out_input; } if (dev->change_protocol) { u64 rc_type = (1 << rc_map->rc_type); rc = dev->change_protocol(dev, &rc_type); if (rc < 0) goto out_raw; dev->enabled_protocols = rc_type; } mutex_unlock(&dev->lock); IR_dprintk(1, "Registered rc%ld (driver: %s, remote: %s, mode %s) ", dev->devno, dev->driver_name ? dev->driver_name : "unknown", rc_map->name ? rc_map->name : "unknown", dev->driver_type == RC_DRIVER_IR_RAW ? "raw" : "cooked"); return 0; out_raw: if (dev->driver_type == RC_DRIVER_IR_RAW) ir_raw_event_unregister(dev); out_input: input_unregister_device(dev->input_dev); dev->input_dev = NULL; out_table: ir_free_table(&dev->rc_map); out_dev: device_del(&dev->dev); out_unlock: mutex_unlock(&dev->lock); return rc; } EXPORT_SYMBOL_GPL(rc_register_device); void rc_unregister_device(struct rc_dev *dev) { if (!dev) return; del_timer_sync(&dev->timer_keyup); if (dev->driver_type == RC_DRIVER_IR_RAW) ir_raw_event_unregister(dev); /* Freeing the table should also call the stop callback */ ir_free_table(&dev->rc_map); IR_dprintk(1, "Freed keycode table "); input_unregister_device(dev->input_dev); dev->input_dev = NULL; device_del(&dev->dev); rc_free_device(dev); } EXPORT_SYMBOL_GPL(rc_unregister_device); /* * Init/exit code for the module. Basically, creates/removes /sys/class/rc */ static int __init rc_core_init(void) { int rc = class_register(&rc_class); if (rc) { printk(KERN_ERR "rc_core: unable to register rc class "); return rc; } rc_map_register(&empty_map); return 0; } static void __exit rc_core_exit(void) { class_unregister(&rc_class); rc_map_unregister(&empty_map); } subsys_initcall(rc_core_init); module_exit(rc_core_exit); int rc_core_debug; /* ir_debug level (0,1,2) */ EXPORT_SYMBOL_GPL(rc_core_debug); module_param_named(debug, rc_core_debug, int, 0644); MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); MODULE_LICENSE("GPL");
笔记:
https://www.cnblogs.com/zzb-Dream-90Time/p/7808518.html