高级驱动——二、input子系统之二、代码

示例代码

1、头文件



#ifndef __INPUT_PLAT_H__
#define __INPUT_PLAT_H__

#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/interrupt.h>

//设计一个按键的数据包
struct key_event{
	char *name;
	int  gpiono;
	int  type;
	int  code;
	int  flags;
};

//设计一个平台自定义数据类型
struct input_pdata{
	struct key_event *keyset;
	int keysize;
};

//设计全局设备对象类型
struct s5pv210_key{
	struct input_pdata  *pd;      //平台自定义指针
 	struct input_dev   *i_dev;			//输入子系统设备对象指针
	struct device     dev;     //父类
};

#endif


2、pdrv


#include <linux/input.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/gpio.h>


#include "input_plat.h"

struct s5pv210_key	*key_dev;


//static struct input_dev *key_dev;
int irqno;
//5》实现中断处理函数
static irqreturn_t key_interrupt_handler(int irq, void *dummy)
{
	int value;
	struct key_event *kevent;
	printk("--------------^_^ %s---------------\n",__FUNCTION__);

	//获取当前触发中断的按键数据包
	kevent = (struct key_event *)dummy;

	// 1,获取按键的信息
	value = gpio_get_value(kevent->gpiono);
	
	// 2,上报按键的数据
	if(value){
		//松开
    	input_report_key(key_dev->i_dev, kevent->code, 0);
    	input_sync(key_dev->i_dev);  //每次上报完,需要调用该函数表示上报数据结束
    }else{
		//按下
		input_event(key_dev->i_dev,kevent->type,kevent->code,1);
		input_sync(key_dev->i_dev);
	}
    return IRQ_HANDLED;
}

int input_plat_probe(struct platform_device * pdev)
{
	int ret,i;
	struct key_event *kevent;
	printk("--------------^_^ %s---------------\n",__FUNCTION__);
	// 1, 实例化全局设备对象
	key_dev = kzalloc(sizeof(struct s5pv210_key), GFP_KERNEL);
	if(!key_dev){
		printk(KERN_ERR "Not enough memory\n");
		return -ENOMEM;
	}
	
	// 2,分配input_dev 对象空间 
	key_dev->i_dev = input_allocate_device();
	if (!key_dev->i_dev) {
		printk(KERN_ERR "Not enough memory\n");
		ret=  -ENOMEM;
		goto err_kfree;
	}
	
	// 3, 初始化input_dev对象
	key_dev->i_dev->evbit[0] = BIT_MASK(EV_KEY);
	//key_dev->keybit[BIT_WORD(KEY_DOWN)] = BIT_MASK(KEY_DOWN);   //方法一
	
	// 4,注册input_dev对象
	ret = input_register_device(key_dev->i_dev);
	if (ret) {
		printk(KERN_ERR "Failed to register device\n");
		goto err_free_dev;
	}

	// 5,保存平台自定义数据和父类
	key_dev->pd = pdev->dev.platform_data;
	key_dev->dev = pdev->dev;
	
	//4》申请中断
	for( i = 0; i < key_dev->pd->keysize;i++){
		kevent = &key_dev->pd->keyset[i];
		irqno = gpio_to_irq(kevent->gpiono);
		if (request_irq(irqno, key_interrupt_handler, kevent->flags, kevent->name, kevent)) {
			printk(KERN_ERR "Can't allocate irq %d\n", irqno);
			ret =  -EBUSY;
			goto err_unregister_dev;
		}
		__set_bit(kevent->code, key_dev->i_dev->keybit);  //方法二
	}
	return 0;
err_unregister_dev:
	input_unregister_device(key_dev->i_dev);
 err_free_dev:
	input_free_device(key_dev->i_dev);
err_kfree:
	kfree(key_dev);
	return ret;
}

int input_plat_remove(struct platform_device *pdev)
{
	int i;
	printk("----------^_^ %s----------------\n",__FUNCTION__);
	for(i = 0; i < key_dev->pd->keysize; i++){
		irqno = gpio_to_irq(key_dev->pd->keyset[i].gpiono);
		free_irq(irqno, &key_dev->pd->keyset[i]);
	}
    input_unregister_device(key_dev->i_dev);
    input_free_device(key_dev->i_dev);

	return 0;
}
	

// 1,实例化pdrv对象
struct platform_driver input_pdrv = {
	.probe		=	input_plat_probe,
	.remove		=	input_plat_remove,
	.driver		=	{
		.name	=	"input_key",	//如果子类中没有初始化id_table,则会使用父类的name与pdev匹配
	},
};

static int __init input_pdrv_init(void)
{
	printk("----------^_^ %s----------------\n",__FUNCTION__);
	// 2,注册pdrv 
	return platform_driver_register(&input_pdrv);
}

static void __exit input_pdrv_exit(void)
{
	printk("----------^_^ %s----------------\n",__FUNCTION__);
	platform_driver_unregister(&input_pdrv);
}
module_init(input_pdrv_init);
module_exit(input_pdrv_exit);
MODULE_LICENSE("GPL");



3、pdev


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


#include "input_plat.h"

//定义按键的数据
struct key_event key_set[]={
	[0] = {
		.name 	=	"key_up",
		.gpiono	=	S5PV210_GPH0(0),
		.type	=	EV_KEY,
		.code	=	KEY_UP,
		.flags	=	IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
	},
	[1] = {
		.name 	=	"key_DOWN",
		.gpiono	=	S5PV210_GPH0(1),
		.type	=	EV_KEY,
		.code	=	KEY_DOWN,
		.flags	=	IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
	},
	[2] = {
		.name 	=	"key_left",
		.gpiono	=	S5PV210_GPH0(2),
		.type	=	EV_KEY,
		.code	=	KEY_LEFT,
		.flags	=	IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
	},
	[3] = {
		.name 	=	"key_right",
		.gpiono	=	S5PV210_GPH0(3),
		.type	=	EV_KEY,
		.code	=	KEY_RIGHT,
		.flags	=	IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
	},
};

//定义自定义数据
struct input_pdata key_pdata = {
	.keyset		=	key_set,
	.keysize	=	ARRAY_SIZE(key_set),
};


void	input_key_release(struct device *dev)
{
	
	printk("--------------^_^ %s-----------------\n",__FUNCTION__);
}


// 1,实例化平台设备对象
struct platform_device input_pdev = {
	.name		=		"input_key",
	.id			=		-1,
	.dev		=		{
		//.platform_data	=	&key_pdata,   //方法一
		.release		=	input_key_release,
	},
};

//实现封装平台自定义数据的函数
void __init input_set_platdata(struct input_pdata *pd)
{
	struct input_pdata *npd;

	if (!pd) {
		printk(KERN_ERR "%s: no platform data\n", __func__);
		return;
	}
	//分配自定义数据空间,同时将pd指向的自定义数据拷贝到分配的新空间中
	npd = kmemdup(pd, sizeof(struct input_pdata), GFP_KERNEL);
	if (!npd)
		printk(KERN_ERR "%s: no memory for platform data\n", __func__);

	input_pdev.dev.platform_data = npd;
}


static int __init input_pdev_init(void)
{
	printk("--------------^_^ %s-----------------\n",__FUNCTION__);
	//设置平台自定义数据----方法二
	input_set_platdata(&key_pdata);
	// 2, 注册pdev
	return platform_device_register(&input_pdev);
}

static void __exit input_pdev_exit(void)
{
	printk("--------------^_^ %s-----------------\n",__FUNCTION__);
	platform_device_unregister(&input_pdev);
}

module_init(input_pdev_init);
module_exit(input_pdev_exit);
MODULE_LICENSE("GPL");


4、app

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


int main(void)
{
	int fd;
	int ret;
	struct input_event event;

	if((fd = open("/dev/event0",O_RDWR)) < 0){
		perror("open");
		exit(1);
	}

	while(1){
		if((ret = read(fd,&event,sizeof(event))) < 0){
			perror("read");
			exit(1);
		}
		if(event.type == EV_KEY){
			switch(event.code){
				case KEY_UP:
					if(event.value)
						printf("按下--->上键\n");
					else
						printf("松开--->上键\n");
					break;	
				case KEY_DOWN:
					if(event.value)
						printf("按下--->下键\n");
					else
						printf("松开--->下键\n");
					break;	
				case KEY_LEFT:
					if(event.value)
						printf("按下--->左键\n");
					else
						printf("松开--->左键\n");
					break;	
				case KEY_RIGHT:
					if(event.value)
						printf("按下--->右键\n");
					else
						printf("松开--->右键\n");
					break;	
			}
		}
	}

	close(fd);

	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值