Input子系统

目录

一、input子系统基本框架

二、驱动开发步骤

三、key2-input版代码解析

四、mpu6050-input版代码解析

五、key3 input子系统版


一、input子系统基本框架

Linux内核为了两个目的:

1. 简化纯输入类外设(如:键盘、鼠标、游戏杆、轨迹球、触摸屏。。。等等)的驱动开发

2. 统一输入类外设产生的数据格式(struct input_event),更加方便应用层编程

设计了输入子系统

 Linux一般把输入类外设产生的数据叫做事件

事件处理层:接收来自核心层上报的事件,并选择对应的handler(事件处理器 struct input_handler)去处理。内核维护着多个事件处理器对象,每个input_handler对象专门处理一类事件,所有产生同类事件的设备驱动共用同一个handler。

设备驱动层:主要实现获取硬件设备的数据信息(包括触摸屏被按下、按下位置、鼠标移动、键盘按下等等),并转换为核心层定义的规范事件后提交给核心层,该层每个设备对应一个struct input_dev对象,

核心层:负责连接设备驱动层和事件处理层,为设备驱动层提供输入设备驱动的接口(struct input_dev)以及输入设备驱动的注册函数(input_register_device),为事件处理层提供输入事件驱动的接口;通知事件处理层对事件进行处理。

二、驱动开发步骤

```c

/*init或probe函数中:

1. 创建struct input_dev对象input_allocate_device

2. 设置事件类型以及相关参数set_bit

3. 注册struct input_dev对象input_register_device

*/



/*exit或remove函数中:

1. 注销struct input_dev对象input_unregister_device

2. 销毁struct input_dev对象input_free_device

*/



/*上报事件

    两种事件上报方式:

    1. 对有中断支持的输入设备:在其中断处理函数(上半部或下半部)中上报事件

    2. 对无中断支持的输入设备:使用workqueue循环定时上报(struct delayed_work)

    主要函数:

    input_event

    input_report_abs

    input_sync

*/



```

相关接口:


```c

/*_init*/

struct input_dev *input_allocate_device(void)//创建对象



void set_bit(struct input_dev *dev,unsigned long whichbits)//设置事件类型



void input_set_abs_params(struct input_dev *dev,unsigned int axis,int min,int max,int fuzz,int flat)



int input_register_device(struct input_dev *dev)//注册input设备到内核



/*_exit*/

void input_unregister_device(struct input_dev *dev)

void input_free_device(struct input_dev *dev)



/*上报事件*/

void input_event(struct input_dev *,unsigned int t,unsigned int c,int v)



void input_report_key(struct input_dev *,unsigned int c,int v) //上报按键事件

void input_report_abs(struct input_dev *,unsigned int c,int v)//上报绝对坐标事件

   

void input_sync(struct input_dev *)//上报完成后需要调用这些函数来通知系统处理完整事件



/*应用层数据类型*/

struct input_event {

    struct timeval time;       // 时间戳

    __u16 type;             // 事件类型

    __u16 code;             // 哪个分值

    __s32 value;            // 具体值      

};

```

三、key2-input版代码解析

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/cdev.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/mm.h>
#include <linux/input.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <asm/uaccess.h>


struct fs4412key2_dev
{
	struct input_dev *pdev;
	
	int gpio;
	int irqno;
};

struct fs4412key2_dev *pgmydev = NULL;

irqreturn_t key2_irq_handle(int no,void *arg)
{
	struct fs4412key2_dev *pmydev = (struct fs4412key2_dev *)arg;
	int status1 = 0;
	int status2 = 0;

	status1 = gpio_get_value(pmydev->gpio);
	mdelay(1);
	status2 = gpio_get_value(pmydev->gpio);

	if(status1 != status2)
	{
		return IRQ_NONE;
	}

	if(status1)
	{
		input_event(pmydev->pdev,EV_KEY,KEY_2,0);
		input_sync(pmydev->pdev);
	}
	else
	{
		input_event(pmydev->pdev,EV_KEY,KEY_2,1);
		input_sync(pmydev->pdev);
	}

	return IRQ_HANDLED;
}

int __init fs4412key2_init(void)
{
	int ret = 0;

	struct device_node *pnode = NULL;

	pnode = of_find_node_by_path("/mykey2_node");
	if(NULL == pnode)
	{
		printk("find node failed\n");
		return -1;
	}


	pgmydev = (struct fs4412key2_dev *)kmalloc(sizeof(struct fs4412key2_dev),GFP_KERNEL);
	if(NULL == pgmydev)
	{
		printk("kmallc for struct fs4412key2_dev failed\n");
		return -1;
	}

	pgmydev->gpio = of_get_named_gpio(pnode,"key2-gpio",0);

	pgmydev->irqno = irq_of_parse_and_map(pnode,0);

	pgmydev->pdev = input_allocate_device();

	set_bit(EV_KEY,pgmydev->pdev->evbit);
	set_bit(KEY_2,pgmydev->pdev->keybit);

	ret = input_register_device(pgmydev->pdev);
	
	ret = request_irq(pgmydev->irqno,key2_irq_handle,IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,"fs4412key2",pgmydev);
	if(ret)
	{
		printk("request_irq failed\n");
		input_unregister_device(pgmydev->pdev);
		input_free_device(pgmydev->pdev);
		kfree(pgmydev);
		pgmydev = NULL;
		return -1;
	}
	return 0;
}

void __exit fs4412key2_exit(void)
{

	free_irq(pgmydev->irqno,pgmydev);

	input_unregister_device(pgmydev->pdev);
	input_free_device(pgmydev->pdev);

	kfree(pgmydev);
	pgmydev = NULL;
}


MODULE_LICENSE("GPL");

module_init(fs4412key2_init);
module_exit(fs4412key2_exit);

 

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

#include <stdio.h>

int main(int argc,char *argv[])
{
	int fd = -1;
	struct input_event evt;
	if(argc < 2)
	{
		printf("Argument is too few\n");
		return 1;
	}

	/*open*/
	fd = open(argv[1],O_RDONLY);
	if(fd < 0)
	{
		printf("open %s failed\n",argv[1]);
		return 2;
	}

	/*init mpu6050*/

	while(1)
	{
		read(fd,&evt,sizeof(evt));
		if(evt.type == EV_KEY && evt.code == KEY_2)
		{
			if(evt.value)
			{
				printf("KEY2 DOWN\n");
			}
			else
			{
				printf("KEY2 UP\n");
			}
		}
	}


	/*close*/
	close(fd);
	fd = -1;
	return 0;
}

四、mpu6050-input版代码解析

 

 

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/i2c.h>
#include <linux/cdev.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/input.h>
#include <linux/io.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>

#define SMPLRT_DIV 0x19
#define CONFIG 0x1A
#define GYRO_CONFIG 0x1B
#define ACCEL_CONFIG 0x1C

#define ACCEL_XOUT_H 0x3B
#define ACCEL_XOUT_L 0x3C
#define ACCEL_YOUT_H 0x3D
#define ACCEL_YOUT_L 0x3E
#define ACCEL_ZOUT_H 0x3F
#define ACCEL_ZOUT_L 0x40
#define TEMP_OUT_H 0x41
#define TEMP_OUT_L 0x42
#define GYRO_XOUT_H 0x43
#define GYRO_XOUT_L 0x44
#define GYRO_YOUT_H 0x45
#define GYRO_YOUT_L 0x46
#define GYRO_ZOUT_H 0x47
#define GYRO_ZOUT_L 0x48

#define PWR_MGMT_1  0x6B


struct mpu6050_dev
{
	struct input_dev * pinput;

	struct i2c_client *pclient;

	struct delayed_work work;
};

struct mpu6050_dev *pgmydev = NULL;

int mpu6050_read_byte(struct i2c_client *pclt,unsigned char reg)
{
	int ret = 0;
	char txbuf[1] = {reg};
	char rxbuf[1] = {0};

	struct i2c_msg msg[2] = 
	{
		{pclt->addr,0,1,txbuf},
		{pclt->addr,I2C_M_RD,1,rxbuf}
	};

	ret = i2c_transfer(pclt->adapter,msg,ARRAY_SIZE(msg));
	if(ret < 0)
	{
		printk("ret = %d,in mpu6050_read_byte\n",ret);
		return ret;
	}

	return rxbuf[0];
}


int mpu6050_write_byte(struct i2c_client *pclt,unsigned char reg,unsigned char val)
{
	int ret = 0;
	char txbuf[2] = {reg,val};

	struct i2c_msg msg[1] = 
	{
		{pclt->addr,0,2,txbuf},
	};

	ret = i2c_transfer(pclt->adapter,msg,ARRAY_SIZE(msg));
	if(ret < 0)
	{
		printk("ret = %d,in mpu6050_write_byte\n",ret);
		return ret;
	}

	return 0;
}

void mpu6050_work_func(struct work_struct *pwk)
{
	struct mpu6050_dev *pmydev = container_of((struct delayed_work *)pwk,struct mpu6050_dev,work);
	unsigned short ax = 0;
	unsigned short ay = 0;
	unsigned short az = 0;
	unsigned short gx = 0;
	unsigned short gy = 0;
	unsigned short gz = 0;
	unsigned short temp = 0;

	ax = mpu6050_read_byte(pmydev->pclient,ACCEL_XOUT_L);
	ax = mpu6050_read_byte(pmydev->pclient,ACCEL_XOUT_H) << 8;
	input_report_abs(pmydev->pinput,ABS_X,ax);
			
	ay = mpu6050_read_byte(pmydev->pclient,ACCEL_YOUT_L);
	ay = mpu6050_read_byte(pmydev->pclient,ACCEL_YOUT_H) << 8;
	input_report_abs(pmydev->pinput,ABS_Y,ay);

	az = mpu6050_read_byte(pmydev->pclient,ACCEL_ZOUT_L);
	az = mpu6050_read_byte(pmydev->pclient,ACCEL_ZOUT_H) << 8;
	input_report_abs(pmydev->pinput,ABS_Z,az);
			
	gx = mpu6050_read_byte(pmydev->pclient,GYRO_XOUT_L);
	gx = mpu6050_read_byte(pmydev->pclient,GYRO_XOUT_H) << 8;
	input_report_abs(pmydev->pinput,ABS_RX,gx);
			
	gy = mpu6050_read_byte(pmydev->pclient,GYRO_YOUT_L);
	gy = mpu6050_read_byte(pmydev->pclient,GYRO_YOUT_H) << 8;
	input_report_abs(pmydev->pinput,ABS_RY,gy);

	gz = mpu6050_read_byte(pmydev->pclient,GYRO_ZOUT_L);
	gz = mpu6050_read_byte(pmydev->pclient,GYRO_ZOUT_H) << 8;
	input_report_abs(pmydev->pinput,ABS_RZ,gz);
			
	temp = mpu6050_read_byte(pmydev->pclient,TEMP_OUT_L);
	temp = mpu6050_read_byte(pmydev->pclient,TEMP_OUT_H) << 8;
	input_report_abs(pmydev->pinput,ABS_MISC,temp);

	input_sync(pmydev->pinput);
	schedule_delayed_work(&pgmydev->work,msecs_to_jiffies(1000));
}

void init_mpu6050(struct i2c_client *pclt)
{
	mpu6050_write_byte(pclt,PWR_MGMT_1,0x00);
	mpu6050_write_byte(pclt,SMPLRT_DIV,0x07);
	mpu6050_write_byte(pclt,CONFIG,0x06);
	mpu6050_write_byte(pclt,GYRO_CONFIG,0xF8);
	mpu6050_write_byte(pclt,ACCEL_CONFIG,0x19);
}

static int mpu6050_probe(struct i2c_client *pclt,const struct i2c_device_id *pid)
{
	int ret = 0;

	pgmydev = (struct mpu6050_dev *)kmalloc(sizeof(struct mpu6050_dev),GFP_KERNEL);
	if(NULL == pgmydev)
	{
		printk("kmalloc failed\n");
		return -1;
	}
	memset(pgmydev,0,sizeof(struct mpu6050_dev));

	pgmydev->pclient = pclt;

	init_mpu6050(pgmydev->pclient);

	pgmydev->pinput = input_allocate_device();

	set_bit(EV_ABS,pgmydev->pinput->evbit);
	input_set_abs_params(pgmydev->pinput,ABS_X,-32768,32767,0,0);
	input_set_abs_params(pgmydev->pinput,ABS_Y,-32768,32767,0,0);
	input_set_abs_params(pgmydev->pinput,ABS_Z,-32768,32767,0,0);
	input_set_abs_params(pgmydev->pinput,ABS_RX,-32768,32767,0,0);
	input_set_abs_params(pgmydev->pinput,ABS_RY,-32768,32767,0,0);
	input_set_abs_params(pgmydev->pinput,ABS_RZ,-32768,32767,0,0);
	input_set_abs_params(pgmydev->pinput,ABS_MISC,-32768,32767,0,0);

	ret = input_register_device(pgmydev->pinput);
	if(ret)
	{
		printk("input_register_device failed\n");

		input_free_device(pgmydev->pinput);
		pgmydev->pinput = NULL;

		kfree(pgmydev);
		pgmydev = NULL;
		return -1;
	}

	INIT_DELAYED_WORK(&pgmydev->work,mpu6050_work_func);

	schedule_delayed_work(&pgmydev->work,msecs_to_jiffies(1000));
	return 0;
}

static int mpu6050_remove(struct i2c_client *pclt)
{
	cancel_delayed_work(&pgmydev->work);

	input_unregister_device(pgmydev->pinput);

	input_free_device(pgmydev->pinput);
	pgmydev->pinput = NULL;

	kfree(pgmydev);
	pgmydev = NULL;

	return 0;
}

struct of_device_id mpu6050_dt[] = 
{
	{.compatible = "invensense,mpu6050"},
	{}
};


struct i2c_device_id mpu6050_ids[] = 
{
	{"mpu6050",0},
	{}
};


struct i2c_driver mpu6050_driver = 
{
	.driver = {
		.name = "mpu6050",
		.owner = THIS_MODULE,
		.of_match_table = mpu6050_dt,
	},
	.probe = mpu6050_probe,
	.remove = mpu6050_remove,
	.id_table = mpu6050_ids,
};

#if 0
int __init mpu6050_driver_init(void)
{
	i2c_add_driver(&mpu6050_driver);
}

void __exit mpu6050_driver_exit(void)
{
	i2c_del_driver(&mpu6050_driver);
}
module_init(mpu6050_driver_init);
module_exit(mpu6050_driver_exit);
#else
module_i2c_driver(mpu6050_driver);
#endif

MODULE_LICENSE("GPL");
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/input.h>
#include <fcntl.h>
#include <unistd.h>

#include <stdio.h>

int main(int argc,char *argv[])
{
	int fd = -1;
	struct input_event evt;
	if(argc < 2)
	{
		printf("Argument is too few\n");
		return 1;
	}

	/*open*/
	fd = open(argv[1],O_RDONLY);
	if(fd < 0)
	{
		printf("open %s failed\n",argv[1]);
		return 2;
	}

	/*init mpu6050*/

	while(1)
	{
		read(fd,&evt,sizeof(evt));
		if(evt.type == EV_ABS)
		{
			switch(evt.code)
			{
				case ABS_X:
					printf("Accel-x:%d\n",evt.value);
					break;
				case ABS_Y:
					printf("Accel-y:%d\n",evt.value);
					break;
				case ABS_Z:
					printf("Accel-z:%d\n",evt.value);
					break;
				case ABS_RX:
					printf("Gyro-x:%d\n",evt.value);
					break;
				case ABS_RY:
					printf("Gyro-y:%d\n",evt.value);
					break;
				case ABS_RZ:
					printf("Gyro-z:%d\n",evt.value);
					break;
				case ABS_MISC:
					printf("Temp:%d\n",evt.value);
					break;
			}
		}
	}


	/*close*/
	close(fd);
	fd = -1;
	return 0;
}

五、key3 input子系统版

 

 

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/cdev.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/mm.h>
#include <linux/input.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <asm/uaccess.h>


struct fs4412key3_dev
{
	struct input_dev *pdev;
	
	int gpio;
	int irqno;
};

struct fs4412key3_dev *pgmydev = NULL;

irqreturn_t key3_irq_handle(int no,void *arg)
{
	struct fs4412key3_dev *pmydev = (struct fs4412key3_dev *)arg;
	int status1 = 0;
	int status2 = 0;

	status1 = gpio_get_value(pmydev->gpio);
	mdelay(1);
	status2 = gpio_get_value(pmydev->gpio);

	if(status1 != status2)
	{
		return IRQ_NONE;
	}

	if(status1)
	{
		input_event(pmydev->pdev,EV_KEY,KEY_3,0);
		input_sync(pmydev->pdev);
	}
	else
	{
		input_event(pmydev->pdev,EV_KEY,KEY_3,1);
		input_sync(pmydev->pdev);
	}

	return IRQ_HANDLED;
}

int __init fs4412key3_init(void)
{
	int ret = 0;

	struct device_node *pnode = NULL;

	pnode = of_find_node_by_path("/mykey3_node");
	if(NULL == pnode)
	{
		printk("find node failed\n");
		return -1;
	}


	pgmydev = (struct fs4412key3_dev *)kmalloc(sizeof(struct fs4412key3_dev),GFP_KERNEL);
	if(NULL == pgmydev)
	{
		printk("kmallc for struct fs4412key3_dev failed\n");
		return -1;
	}

	pgmydev->gpio = of_get_named_gpio(pnode,"key3-gpio",0);

	pgmydev->irqno = irq_of_parse_and_map(pnode,0);

	pgmydev->pdev = input_allocate_device();

	set_bit(EV_KEY,pgmydev->pdev->evbit);
	set_bit(KEY_3,pgmydev->pdev->keybit);

	ret = input_register_device(pgmydev->pdev);
	
	ret = request_irq(pgmydev->irqno,key3_irq_handle,IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,"fs4412key3",pgmydev);
	if(ret)
	{
		printk("request_irq failed\n");
		input_unregister_device(pgmydev->pdev);
		input_free_device(pgmydev->pdev);
		kfree(pgmydev);
		pgmydev = NULL;
		return -1;
	}
	return 0;
}

void __exit fs4412key3_exit(void)
{

	free_irq(pgmydev->irqno,pgmydev);

	input_unregister_device(pgmydev->pdev);
	input_free_device(pgmydev->pdev);

	kfree(pgmydev);
	pgmydev = NULL;
}


MODULE_LICENSE("GPL");

module_init(fs4412key3_init);
module_exit(fs4412key3_exit);

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

宇努力学习

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

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

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

打赏作者

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

抵扣说明:

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

余额充值