linux驱动的input子系统与平台总线结合

/*
plat_input_drv.c
*/
#include <linux/input.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/slab.h>

#include "plat_input.h"

struct s5pv210_key_dev *key_dev;

int irqno;

//实现中断处理函数------//上报数据
static irqreturn_t key_irq_handler(int irq, void *dummy)
{
	int value;
	struct s5pv210_key_data *p;
	printk("----------- ^_^ %s---------------\n",__FUNCTION__);

	// 1,保存当前触发中断的按键信息
	p = (struct s5pv210_key_data *)dummy;

	// 2,获取对应的按键的状态
	value = gpio_get_value(p->gpiono);
		
	if(value){
		//松开
		printk("kernel: %s up\n",p->name);
		input_event(key_dev->i_dev,p->event.type,p->event.code,0);
		input_sync(key_dev->i_dev);
	}else{
		//按下
		printk("kernel: %s  pressed\n",p->name);
		input_report_key(key_dev->i_dev, p->event.code, 1);
    	input_sync(key_dev->i_dev);
	}
    
    return IRQ_HANDLED;
}
int key_plat_input_probe(struct platform_device *pdev)
{
        int ret;
		int i;
		struct s5pv210_key_data *kinfo;
		printk("----------- ^_^ %s---------------\n",__FUNCTION__);
		// 0,实例化全局设备对象
		key_dev = kzalloc(sizeof(struct s5pv210_key_dev), GFP_KERNEL);
		if(!key_dev){
			printk("kzalloc error");
			return -ENOMEM;
		}

		//获取平台自定义数据
		key_dev->pd = (struct s5pv210_pdata*)pdev->dev.platform_data;
		
		//初始化父类
		key_dev->dev = pdev->dev;
		
		// 1》实例化input-dev对象
		key_dev->i_dev= input_allocate_device();
		if (!key_dev->i_dev) {
                printk(KERN_ERR "input_allocate_device: Not enough memory\n");
                ret =  -ENOMEM;
				goto err_kfree;
        }
		
		// 2》初始化input-dev对象 
		key_dev->i_dev->evbit[0] = BIT_MASK(key_dev->pd->type);   //使能按键设备驱动
		//key_dev->i_dev->evbit[0] = BIT_MASK(EV_KEY);
        //key_dev->keybit[BIT_WORD(KEY_DOWN)] = BIT_MASK(KEY_DOWN); //使能下键

		
		// 3》注册input-dev对象
		ret = input_register_device(key_dev->i_dev);
        if (ret) {
                printk(KERN_ERR "input_register_device: Failed to register device\n");
                goto err_free_dev;
        }
		
		// 4》申请中断
		for(i=0; i < key_dev->pd->keysize;i++){
			kinfo = &(key_dev->pd->keyset[i]);
			irqno =  gpio_to_irq(kinfo->gpiono);
	        if (request_irq(irqno, key_irq_handler,kinfo->flags, kinfo->name, kinfo)) {
	                printk(KERN_ERR "request_irq: Can't allocate irq\n");
	                ret =  -EBUSY;
					goto err_input_unregister;
	        }

			//使能不同按键
			set_bit(kinfo->event.code,key_dev->i_dev->keybit);
		}
        //

        return 0;
		
err_input_unregister:
	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 key_plat_input_remove(struct platform_device * pdev)
{
	int i;
	struct s5pv210_key_data *kinfo;
	printk("----------- ^_^ %s---------------\n",__FUNCTION__);
	for(i=0; i < key_dev->pd->keysize;i++){
		kinfo = &key_dev->pd->keyset[i];
		free_irq(gpio_to_irq(kinfo->gpiono), kinfo);
	}
    input_unregister_device(key_dev->i_dev);
    input_free_device(key_dev->i_dev);
	kfree(key_dev);

	return 0;
}



// 1,实例化pdrv对象
struct platform_driver key_pdrv = {
	.probe		=		key_plat_input_probe,
	.remove		=		key_plat_input_remove,
	.driver		=	{
		.name 	=	"s5pv210_key",  //如果没有初始化id_table,则会使用父类的name匹配
	},
	
};

static int __init plat_input_drv_init(void)
{
	printk("----------- ^_^ %s---------------\n",__FUNCTION__);
	// 2,注册pdrv对象
	return platform_driver_register(&key_pdrv);
}
static void __exit plat_input_drv_exit(void)
{
	printk("----------- ^_^ %s---------------\n",__FUNCTION__);
	platform_driver_unregister(&key_pdrv);

}


module_init(plat_input_drv_init);
module_exit(plat_input_drv_exit);
MODULE_LICENSE("GPL");


```c
/*
plat_input_dev.c
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>

#include "plat_input.h"

//定义保存不同按键信息的数组
struct s5pv210_key_data key_set[] = {
	[0] = {
		.name = "key_up",
		.gpiono = S5PV210_GPH0(0),
		.flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
		.event = {
			.type  	= 	EV_KEY,
			.code	=	KEY_UP,
		},
	},
	[1] = {
		.name = "key_down",
		.gpiono = S5PV210_GPH0(1),
		.flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
		.event = {
			.type  	= 	EV_KEY,
			.code	=	KEY_DOWN,
		},
	},
	[2] = {
		.name = "key_left",
		.gpiono = S5PV210_GPH0(2),
		.flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
		.event = {
			.type  	= 	EV_KEY,
			.code	=	KEY_LEFT,
		},
	},
	[3] = {
		.name = "key_right",
		.gpiono = S5PV210_GPH0(3),
		.flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
		.event = {
			.type  	= 	EV_KEY,
			.code	=	KEY_RIGHT,
		},
	},
};

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


//实例化平台自定义数据
struct s5pv210_pdata key_pdata = {
	.keyset		=	key_set,
	.keysize	=	ARRAY_SIZE(key_set),
	.type		=	EV_KEY,
};

// 1, 实例化pdev对象
struct platform_device key_pdev = {
	.name 	=	"s5pv210_key",
	.id		=	-1,
	.dev	=	{
		.platform_data	=	&key_pdata,
		.release		=	key_release,
		
	},
};

static int __init plat_input_dev_init(void)
{
	printk("----------- ^_^ %s -------------\n",__FUNCTION__);
	// 2,注册pdev
	return platform_device_register(&key_pdev);
	
}

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

module_init(plat_input_dev_init);
module_exit(plat_input_dev_exit);
MODULE_LICENSE("GPL");



```c
/*
plat_input.h
*/

#ifndef __PLAT_INPUT_H__
#define __PLAT_INPUT_H__

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


//按键的数据包
struct s5pv210_key_data{
	char *name;
	int gpiono;
	int flags;
	struct input_event event;
};



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

//设计全局设备对象类型
struct s5pv210_key_dev{
	struct input_dev  *i_dev;
	struct s5pv210_pdata *pd;
	struct device dev;
};

#endif


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


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

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


    while(1){
	bzero(&event,sizeof(event));
	if((ret = read(key_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");
	    }
	}
    }

    close(key_fd);

    return 0;
}

```c
/*
Makefile
*/
KERNEL_DIR = /home/peter/fs210/kerner/linux-3.0.8
CUR_DIR = ${shell pwd}


MODULE_NAME1 = plat_input_drv
MODULE_NAME2 = plat_input_dev
MYAPP = key_app

all:
	make -C $(KERNEL_DIR) M=$(CUR_DIR) modules
	arm-none-linux-gnueabi-gcc -o $(MYAPP) $(MYAPP).c

clean:
	make -C $(KERNEL_DIR) M=$(CUR_DIR) clean
	rm $(MYAPP)


install:
	cp *.ko /opt/rootfs/drv_module
	cp $(MYAPP)  /opt/rootfs/drv_module


obj-m += $(MODULE_NAME1).o
obj-m += $(MODULE_NAME2).o


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值