linux驱动输入子系统之多输入设备

前言:

        这篇写的是一次性给5个按键写好驱动~用输入子系统实现。

代码:

设备树节点:

	myinput-keys {
		compatible = "myinput-keys";

		home {
			 code = <KEY_HOME>;
			 gpios = <&gpx1 1 GPIO_ACTIVE_LOW>;
			 interrupt-parent = <&gpx1>;
			 interrupts = <1 IRQ_TYPE_EDGE_BOTH>;
		};

		back {
			code = <KEY_BACK>;
			interrupt-parent = <&gpx1>;
			interrupts = <2 IRQ_TYPE_EDGE_BOTH>;

			gpios = <&gpx1 2 GPIO_ACTIVE_LOW>;
		};

		sleep {
			interrupt-parent = <&gpx2>;
			interrupts = <6 IRQ_TYPE_EDGE_BOTH>;
			code = <KEY_POWER>;

			gpios = <&gpx2 6 GPIO_ACTIVE_LOW>;
		};

		vol-up {
			interrupt-parent = <&gpx2>;
			code = <KEY_UP>;
			interrupts = <1 IRQ_TYPE_EDGE_BOTH>;
			gpios = <&gpx2 1 GPIO_ACTIVE_HIGH>;
		};

		vol-down {
			interrupt-parent = <&gpx2>;
			interrupts = <0 IRQ_TYPE_EDGE_BOTH>;
			code = <KEY_DOWN>;
			gpios = <&gpx2 0 GPIO_ACTIVE_HIGH>;
		};
	};

14th_input_sys_mulkey.c

#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("LCH");
#include <linux/input.h>
#include <asm-generic/bitops/non-atomic.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/uaccess.h>
#include <uapi/linux/input-event-codes.h>
#include <linux/string.h>

#define MYKEY_NUM 5
struct input_dev *idev;

struct device_node *f_node; 					//设备树节点
struct hw_describe{
	struct device_node *mynode; 				//设备树节点
	int mygpio; 								//gpio号
	int irqno;									//中断号
	unsigned int key_code;								//是什么键值/内涵
	char irqname[20];
};
struct hw_describe allkey[MYKEY_NUM];
int i;

static irqreturn_t keyirq_handler(int irqno,void *devid){
	int value;
	struct hw_describe *imykey = (struct hw_describe *)devid;
	
    printk("receive a interrupt %s!\n",imykey->irqname);
//	4.1非设备树方式
//	value = *(key_dev->virreg_base+1)&(0x1<<1);
 
//	4.2设备树方式
	value = gpio_get_value(imykey->mygpio);
	if(value==1){	//没按下		==  key_event.value = 0
		input_event(idev,EV_KEY,imykey->key_code,0);//tpye,code,value
		input_sync(idev);

    	printk("key up!\n");
	}
	else if(value==0){			//按键按下
		input_event(idev,EV_KEY,imykey->key_code,1);//tpye,code,value
		input_sync(idev);
		printk("key down!\n");
	}
 
	return IRQ_HANDLED;
}

static int __init input_sys_init(void)
{
	int ret,tmp;
	char *irqname;
	
	struct device_node *now_node; 				//设备树节点
	struct device_node *prev_node; 				//设备树节点
	printk(KERN_EMERG "input_sys_init\n");
	//0.给input_dev分配空间
	idev = input_allocate_device();
	if(idev==NULL){
		
		printk(KERN_EMERG "input_allocate_device error\n");
		return -ENOMEM;
	}

	
	//1.初始化input_dev
	//	1.1设备enbit即类型
	__set_bit(EV_KEY,idev->evbit);
	
	//得到父节点先
	f_node = of_find_compatible_node(NULL,NULL,"myinput-keys");
	if(f_node==NULL){
		printk(KERN_EMERG "of_find_compatible_node error\n");
		ret = -ENOMEM;
		goto err_0;
	}
	prev_node = NULL;//表示从第一个开始找
	i=0;
	irqname=NULL;
	do
	{
		//找到子节点
		now_node = of_get_next_child(f_node,prev_node);
		if(now_node==NULL){
				printk(KERN_EMERG "%d of_get_next_child error\n",i);
				ret = -ENOMEM;
				goto err_0;
			}
		allkey[i].mynode = now_node;
		prev_node = now_node;
			
		//得到KEY键值/内涵:
		ret = of_property_read_u32(now_node, "code", &allkey[i].key_code);
		if (ret) {
			printk(KERN_EMERG "%d of_property_read_u32 error\n",i);
		   	goto err_0;
		}else
			printk(KERN_EMERG "%d the keycode is %d\n",i,allkey[i].key_code);
		//设置注册中断的名字
		sprintf(allkey[i].irqname, "KEYIRQ_%d",allkey[i].key_code);
		
		printk(KERN_EMERG "%d the irqname is %s\n",i,allkey[i].irqname);
		//	1.2设置keybit即键值/内涵
		__set_bit(allkey[i].key_code,idev->keybit);


		//得到gpio
		allkey[i].mygpio = of_get_named_gpio_flags(now_node,"gpios",0,NULL);
		if (!gpio_is_valid(allkey[i].mygpio))
			printk("gpio%d isn't valid\n",i);
		else printk("gpio num=%d",allkey[i].mygpio);
	 
		ret= gpio_request(allkey[i].mygpio, "gpios");
		if(ret!=0){
			printk(KERN_EMERG "gpio_request%d error\n",i);
			ret = -ENOMEM;
			goto err_1;
		}
		gpio_direction_input(allkey[i].mygpio);//初始化为输入模式
		
		//获取中断号--申请中断
		allkey[i].irqno = of_irq_get(now_node,0);
		ret = request_irq(allkey[i].irqno,keyirq_handler,IRQ_TYPE_EDGE_BOTH,allkey[i].irqname,&allkey[i]);
		if(ret!=0){ //返回0说明正确
			printk(KERN_EMERG "irqno error\n");
			goto err_2;
		}
		printk(KERN_EMERG "irqno  is %d\n",allkey[i].irqno);
		
		i++;
		
	}while(of_get_next_child(f_node,prev_node)!=NULL);

	

	//	1.3设备idev的信息 /sys/class/input/devices
	idev->name = "lch-idev";
	idev->phys = "/lch-idev-666";//设备路径
	idev->uniq = "/lch-idev-999";//好像是命令
	idev->id.bustype = BUS_HOST;//GPIO一般用这个,其他还有IIC等BUS
	idev->id.vendor = 0x1111;//cat时显示的是0x后面的东西
	idev->id.version=0x2222;//cat时显示的是0x后面的东西
	//2.注册到输入子系统中,这样就注册了输入设备、生成了设备节点/dev/input/enventx
	
	ret = input_register_device(idev);
	if(ret!=0){//正常是返回0的
		printk(KERN_EMERG "input_register_device error\n");
		goto err_0;
	}

	return 0;


err_2:
	
	for(tmp =0;tmp<i;tmp++){
		gpio_free(allkey[tmp].mygpio);
	}


err_1:
	input_unregister_device(idev);

err_0:
	input_free_device(idev);
	return ret;

}
static void __exit  input_sys_exit(void)
{
	int tmp=0;
	printk(KERN_EMERG "input_sys_exit\n");
	for(tmp =0;tmp<i;tmp++){
		free_irq(allkey[tmp].irqno,NULL);
		gpio_free(allkey[tmp].mygpio);
	}
	input_unregister_device(idev);
	input_free_device(idev);
}

//
module_init(input_sys_init);
module_exit(input_sys_exit);

app_input_sys_mulkey.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/input.h>

struct input_event myevent;

//打开设备节点  传入cmd ,
int main(int argc ,char **argv){
    int fd,res;

    //打开节点
    fd = open("/dev/input/event1",O_RDWR);
    if(fd>0)
		printf("app open success\n");
    else {
        printf("app open error\n");
		return -1;
    }
	
	while(1){
		res = read(fd, (void *)(&myevent),sizeof(struct input_event));
		if(res<0){
			perror("read");
			exit(-1);
		}
		if(myevent.type==EV_KEY){
			switch (myevent.code){
				case KEY_HOME:
					if(myevent.value==1){ //按下1,抬起0
						printf("app KEY_HOME down\n");
					}
					else if(myevent.value==0){
						printf("app KEY_HOME up\n");
					}
					break;
				case KEY_BACK:
					if(myevent.value==1){ //按下1,抬起0
						printf("app KEY_BACK down\n");
					}
					else if(myevent.value==0){
						printf("app KEY_BACK up\n");
					}
					break;
				case KEY_POWER:
					if(myevent.value==1){ //按下1,抬起0
						printf("app KEY_POWER down\n");
					}
					else if(myevent.value==0){
						printf("app KEY_POWER up\n");
					}
					break;
				case KEY_UP:
					if(myevent.value==1){ //按下1,抬起0
						printf("app KEY_UP down\n");
					}
					else if(myevent.value==0){
						printf("app KEY_UP up\n");
					}
					break;
				case KEY_DOWN:
					if(myevent.value==1){ //按下1,抬起0
						printf("app KEY_DOWN down\n");
					}
					else if(myevent.value==0){
						printf("app KEY_DOWN up\n");
					}
					break;

			}

		}
	}
    close(fd);
    return ;
}

运行效果:

查看注册的驱动:cat /proc/interrupts

insmod驱动:

运行app:

遇到问题:

         遇到一个问题,也蛮古怪的,调试了好久,因为要注册中断嘛,想用不同的名,就使用sprintf去整,我一开始是定义了一个字符指针

	char *irqname;

然后再

		sprintf(irqname, "KEYIRQ_%d",allkey[i].key_code);
        allkey[i].irqname = irqname ;

结果不知道怎么回事一直报错说有空指针。

相关数据结构定义如下:

struct hw_describe{
	struct device_node *mynode; 				//设备树节点
	int mygpio; 								//gpio号
	int irqno;									//中断号
	unsigned int key_code;								//是什么键值/内涵
	char irqname[20];
};
struct hw_describe allkey[MYKEY_NUM];

后来改成了:

		//设置注册中断的名字
		sprintf(allkey[i].irqname, "KEYIRQ_%d",allkey[i].key_code);

就正常了。

        不是很懂,看起来没有问题呀原来的写法,知道的朋友麻烦指教一下。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值