4412驱动-input 输入子系统


// cat /proc/bus/input/devices 列出当前系统下注册的所有输入设备


/* 测试方法,将当前终端的标准输入重定向到驱动框架所产生的tty设备上
 * exec 0</dev/tty1
 */



#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>

#include <mach/regs-gpio.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <mach/irqs.h>

#include <linux/input.h>

// cat /proc/bus/input/devices 列出当前系统下注册的所有输入设备

/* 测试方法,将当前终端的标准输入重定向到驱动框架所产生的tty设备上
 * exec 0</dev/tty1
 */

//#define S3C_ADDR_BASE    0xF6000000  
 //#define S3C_ADDR(x)  (S3C_ADDR_BASE + (x))  
//#define S5P_VA_GPIO2      S3C_ADDR(0x02240000)  //0x11840000  
//GPX3CON 0x11000C60  
#define GPX3CON (S5P_VA_GPIO2 + 0x0c60) //0x11840000+0x0c60=0x11840C60  
#define GPX3DAT (S5P_VA_GPIO2 + 0x0c64)  

struct ldm_info {
	struct input_dev *dev;
};
static struct ldm_info ldm;

struct key_info {
	const char *name;
	size_t code; //键值
	bool (*read_stat)(struct key_info*);//声明一个函数指针
	unsigned long reg; //本按键所属的状态寄存器的虚拟地址
	size_t ctrlbit; //记录各按键在各自所属的寄存器中的对应bit
	int irqno; //中断号
};

//返回按键的状态:按住时为0,抬起时为1
static bool stat(struct key_info *pkey)
{
	u32 data = readl(pkey->reg);//从内存映射的 I/O 空间读取数据,readl 从 I/O 读取 32 位数据 ( 4 字节 )
	return data & pkey->ctrlbit;
}

static struct key_info key[] = {
	{"KEY_L", KEY_L, stat, (unsigned long)GPX3DAT, 1 << 2, IRQ_EINT(26)},
	{"KEY_S", KEY_S, stat, (unsigned long)GPX3DAT, 1 << 3, IRQ_EINT(27)},
	{"KEY_ENTER", KEY_ENTER, stat, (unsigned long)GPX3DAT, 1 << 4, IRQ_EINT(28)},
	{"KEY_BACKSPACE", KEY_BACKSPACE, stat, (unsigned long)GPX3DAT, 1 << 5, IRQ_EINT(29)},
};

static irqreturn_t key_handler(int irqno, void *arg)
{
	struct key_info *pkey = (struct key_info *)arg;

	//读出触发中断的当前按键的状态
	if (pkey->read_stat(pkey)) { //抬起
		//value=1表示按下,=0表示抬起,硬件状态应根据寄存器反应的电平状态来判断
		input_report_key(ldm.dev, pkey->code, 0);
	} else { //按下
		input_report_key(ldm.dev, pkey->code, 1);
	}

	//哨兵event
	input_sync(ldm.dev);

	return IRQ_HANDLED;
}

static int __init ldm_init(void)
{
	printk("%s %s\n", __FUNCTION__, __FILE__);

	int ret = 0;

	//1 创建输入设备对象
	ldm.dev = input_allocate_device();
	if (!ldm.dev) {
		printk("input_allocate_device failed\n");
		ret = -ENOMEM;
		goto err_input_allocate_device;
	}

	//2 对象初始化
	ldm.dev->name = "ldm_key";

	//2.1 定义输入设备的输入类型
	//有按键类型的操作
	set_bit(EV_KEY, ldm.dev->evbit);
	//支持连发
	set_bit(EV_REP, ldm.dev->evbit);
	//注册本设备所拥有的所有按键键值
	ssize_t i = 0;
	for (i = 0; i < ARRAY_SIZE(key); ++i) {
		set_bit(key[i].code, ldm.dev->keybit);
	}

	//3 硬件初始化,中断申请,按下抬起都触发中断
	for (i = 0; i < ARRAY_SIZE(key); ++i) {
		ret = request_irq(key[i].irqno, key_handler, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, key[i].name, (void*)(key + i));
		if (ret < 0) {
			printk("request_irq %d faild\n", i);
			goto err_request_irq;
		}
	}

	//4 注册输入设备
	ret = input_register_device(ldm.dev);
	if (ret < 0) {
		printk("input_register_device failed\n");
		goto err_input_register_device;
	}

	return 0;

err_input_register_device:
err_request_irq:
	for (i = i - 1; i >= 0; --i) {
		free_irq(key[i].irqno, (void*)(key + i));
	}
	input_free_device(ldm.dev);
err_input_allocate_device:
	return ret;
}

static void __exit ldm_exit(void)
{
	printk(KERN_DEBUG "%s %s\n", __FUNCTION__, __FILE__);

	input_unregister_device(ldm.dev);

	ssize_t i = ARRAY_SIZE(key);//ARRAY_SIZE求设备结构体中设备的个数
	for (i = i - 1; i >= 0; --i) {
		free_irq(key[i].irqno, (void*)(key + i));
	}

	input_free_device(ldm.dev);
}

module_init(ldm_init);
module_exit(ldm_exit);



MODULE_LICENSE("GPL");
MODULE_AUTHOR("xiangtan da xue chenhaipan");  
MODULE_VERSION("2017.5.4"); 




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZHULINHAIBAO

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值