linux驱动输入子系统

前言:

        输入子系统,就是 入号注节硬操 中 申请设备号,注册设备,生成设备节点,fops,不用自己写了,系统帮忙写好了,可以方便的开发。要不要用就看需求了,对于输入设备例如key等等确实很方便。

/sys/class/input/enentx/device 中可以查看属于输入子系统的设备信息

输入子系统参数内涵:
        Type就是哪种输入设备,例如鼠标、键盘、触摸屏等类型
        code就是按键的内涵,例如是电源开关、EXT、左键等,人为赋予的内涵
        value就是该按键的状态,0没按下,1是按下(规定死的)

下面写一个单一设备的输入子系统代码~后续会出多个按键的。

        这个呢会自动生成设备节点,所以不需要注册字符设备(或者说是它帮我们写了),字符设备驱动框架那一套流程不必再走一遍,不过还是可以和平台总线驱动结合的,实现设备和驱动分离。下面我们也懒得做了,反正是从设备树得到设备硬件信息,直接写就不套个平台总线设备驱动框架了。

先看设备树,是这样的:

	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>;
		};
	};

在这个代码中,我们只用到 home 这个节点:

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

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

代码:

13th_input_sys.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>

//这是要注册输入子设备函数,其参数要的结构体
//这个结构体描述的当然就是type,code,value了
struct input_dev *idev;
//以下是存从设备树拿到的硬件信息要用的
struct device_node *mynode; 				//设备树节点
int mygpio; 								//gpio号
int irqno;									//中断号

//这是中断处理函数
static irqreturn_t keyirq_handler(int irqno,void *devid){
	int value;
    printk("receive a interrupt 9!\n");
//	4.1非设备树方式
//	value = *(key_dev->virreg_base+1)&(0x1<<1);
 
//	4.2设备树方式
	value = gpio_get_value(mygpio);
	if(value==1){	//没按下		==  key_event.value = 0
		input_event(idev,EV_KEY,KEY_ENTER,0);//tpye,code,value
		input_sync(idev);
        //以上这两个语句就是应用程序read时,驱动传上去的
        //说白了就是把哪种输入设备、这种输入设备的哪种键值、键值的状态给到应用程序
    	printk("key up!\n");
	}
	else if(value==0){			//按键按下
		input_event(idev,EV_KEY,KEY_ENTER,1);//tpye,code,value
		input_sync(idev);
		printk("key down!\n");
	}
 
	return IRQ_HANDLED;
}

static int __init input_sys_init(void)
{
	int ret;
	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);
	//	1.2设置keybit即键值/内涵
	__set_bit(KEY_ENTER,idev->keybit);
	//	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;
	}
	//3.硬件相关 用设备树写法
		//	设备树方式:
	//得到节点先
	mynode = of_find_compatible_node(NULL,NULL,"myinput-keys");
	if(mynode==NULL){
		printk(KERN_EMERG "of_find_compatible_node error\n");
		ret = -ENOMEM;
		goto err_1;
	}
	//找到子节点
	mynode = of_find_node_by_name(mynode,"home");
		if(mynode==NULL){
			printk(KERN_EMERG "of_find_node_by_name error\n");
			ret = -ENOMEM;
			goto err_1;
		}
	//得到gpio
	mygpio = of_get_named_gpio_flags(mynode,"gpios",0,NULL);
	if (!gpio_is_valid(mygpio))
		printk("gpio isn't valid\n");
	else printk("gpio num=%d",mygpio);
 
	ret= gpio_request(mygpio, "gpios");
	if(ret!=0){
		printk(KERN_EMERG "gpio_request error\n");
		ret = -ENOMEM;
		goto err_1;
	}
	gpio_direction_input(mygpio);//初始化为输入模式
	
	//获取中断号--申请中断
	irqno = of_irq_get(mynode,0);
	ret = request_irq(irqno,keyirq_handler,IRQ_TYPE_EDGE_BOTH,"keyirq",NULL);
	if(ret!=0){ //返回0说明正确
		printk(KERN_EMERG "irqno error\n");
		goto err_2;
	}
	printk(KERN_EMERG "irqno  is %d\n",irqno);
	return 0;


err_2:
	gpio_free(mygpio);

err_1:
	input_unregister_device(idev);

err_0:
	input_free_device(idev);
	return ret;

}
static void __exit  input_sys_exit(void)
{
	printk(KERN_EMERG "input_sys_exit\n");
	free_irq(irqno,NULL);
	gpio_free(mygpio);
	input_unregister_device(idev);
	input_free_device(idev);
}

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

app_input_sys.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>
//驱动回应应用程序的read,传来的是input_event这个结构体类型的数据包

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){
        //input_event这个结构体里面就包含了type,code,value,举例,如果是键盘的话
        //那这三个值主要是用来给用户判断具体是哪个按键有动作,并且该动作是按下还是抬起
		res = read(fd, (void *)(&myevent),sizeof(struct input_event));
		if(myevent.type==EV_KEY){
			if(myevent.code==KEY_ENTER){
				if(myevent.value==1){ //按下1,抬起0
		        	printf("app key down\n");
				}
				else if(myevent.value==0){
		        	printf("app key up\n");
				}
			}
		}
	}
    close(fd);
    return ;
}

运行效果:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值