驱动之路三--------button驱动(input设备)

开发板:smdk6410

系统:Linux


按键是经常要用的,通过按键产生中断,可以处理不同的功能,键盘的输入就是这么一个原理,


键盘也可以作为一个字符设备去写,在 驱动之路二 中就详细阐述过设备分类的概念,也将LED驱动写成了misc设备的,在这要将button驱动基于input设备去写,现在开始写了,

先是头文件 s3c_button.h

#ifndef __BUTTON_H
#define __BUTTON_H

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

struct button_info {
	char name[32];
	int user;
	int status;
	void __iomem *v;
	struct input_dev *dev;//input设备结构体
	int irq;//中断线
	int code;
	irqreturn_t (*do_button)(int no, void *data);。。中断处理函数
};

#define S3C_PA_BUTTON	0x7f008000
#define S3C_SZ_BUTTON	SZ_4K

#define GPNDAT		0x834

#define S3C_IRQ_BUTTON_S	IRQ_EINT(0)
#define S3C_IRQ_BUTTON_E	IRQ_EINT(5)
#define S3C_NUM_BUTTON 6


#endif

头文件还是就一个button_info结构体,用于描述button这个设备,再就是相关宏定义,

设备文件的修改和之前的之前写的LED驱动相比,改动不大,

#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/platform_device.h>

#include "s3c_button.h"

void b_release(struct device *dev)
{
	printk("Device is released\n");
}
//写button就需要两种资源了,这个需要注意
struct resource b_res[] = {
	[0] = {
		.start = S3C_PA_BUTTON,
		.end = S3C_PA_BUTTON + S3C_SZ_BUTTON - 1,
		.flags = IORESOURCE_MEM,
	},
	[1] = {
		.start = S3C_IRQ_BUTTON_S,
		.end = S3C_IRQ_BUTTON_E,
		.flags = IORESOURCE_IRQ,
	}
};

struct platform_device dev = {
	.name = "s3c-button",
	.id = -1,
	.num_resources = ARRAY_SIZE(b_res),
	.resource = b_res,
	.dev = {
		.release = b_release,
	}
};

static __init int module_test_init(void)
{
	return platform_device_register(&dev);
}

static __exit void module_test_exit(void)
{
	platform_device_unregister(&dev);
}

module_init(module_test_init);
module_exit(module_test_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Musesea");
MODULE_VERSION("1.0");
MODULE_DESCRIPTION("Test for module");

设备文件没什么好说的。

下面是驱动文件

#include <linux/init.h>
#include <linux/module.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/input.h>

#include "s3c_button.h"

int if_down(struct button_info *b)
{
	//GPNDAT[5-0]
	return !(readl(b->v + GPNDAT) & (1 << (b->irq - S3C_IRQ_BUTTON_S)));
}

irqreturn_t button_handle(int no, void *data)
{
	struct button_info *b = data;

	if(if_down(b)){
		input_report_key(b->dev, b->code, 1);//上报事件,注意内核需要支持上报
		input_sync(b->dev);//不同步是什么事件都不能上报的
	}else{
		input_report_key(b->dev, b->code, 0);
		input_sync(b->dev);
	}
	
	return IRQ_HANDLED;
}

void s3c_button_exit(struct button_info *b)
{

}

void s3c_button_init(struct button_info *b, int start)
{
	int i;
	
	for(i = 0; i < S3C_NUM_BUTTON; i++){
		sprintf(b[i].name, "button%d", i);
		b[i].user = 0;
		b[i].irq = start + i;
		b[i].dev = b[0].dev;
		b[i].v = b[0].v;
		b[i].do_button = button_handle;
	}
        //键码,就是每个键代表的意思
        b[0].code = KEY_UP;
	b[1].code = KEY_DOWN;
	b[2].code = KEY_LEFT;
	b[3].code = KEY_RIGHT;
	b[4].code = KEY_ESC;
	b[5].code = KEY_ENTER;
}

int b_probe(struct platform_device *pdev)
{
	int ret;
	int i;
	struct resource *g_res, *irq_res;
	struct button_info *button;

	g_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);//获取资源
	irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
	if(!g_res || !irq_res)
		return -EBUSY;
	
	button = kzalloc(sizeof(struct button_info) * S3C_NUM_BUTTON, GFP_KERNEL);
	if(!button)
		return -ENOMEM;

	button->v = ioremap(g_res->start, g_res->end - g_res->start + 1);
	if(!button->v){
		ret = -ENOMEM;
		goto remap_error;
	}

	button->dev = input_allocate_device();//分配input设备
	if(!button->dev){
		ret = -ENOMEM;
		goto alloc_dev_error;
	}

	button->dev->name = pdev->name;
	button->dev->uniq = "20131113";
	button->dev->phys = "/dev/eventx";
	button->dev->id.bustype = BUS_HOST;
	button->dev->id.vendor = 110;
	button->dev->id.product = 120;
	button->dev->id.version = 119;
	
	//evbit[0] |= 1 << EV_KEY;
	//设置该设备要支持的事件类型
	set_bit(EV_KEY, button->dev->evbit);
	set_bit(EV_SYN, button->dev->evbit);
	//设置该设备要支持的key事件
	set_bit(KEY_UP, button->dev->keybit);
	set_bit(KEY_DOWN, button->dev->keybit);
	set_bit(KEY_LEFT, button->dev->keybit);
	set_bit(KEY_RIGHT, button->dev->keybit);
	set_bit(KEY_ESC, button->dev->keybit);
	set_bit(KEY_ENTER, button->dev->keybit);
	
	ret = input_register_device(button->dev);//注册input设备
	if(ret)
		goto register_error;

	platform_set_drvdata(pdev, button);//将button保存到pdev中

	s3c_button_init(button, irq_res->start);

	for(i = 0; i < S3C_NUM_BUTTON; i++)
                //申请中断
                ret = request_irq(button[i].irq, button[i].do_button, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, button[i].name, &button[i]);
		if(ret)
			goto request_irq_error;
	
	return 0;
request_irq_error:
	while(i--)
		free_irq(button[i].irq, &button[i]);
register_error:
	input_free_device(button->dev);
alloc_dev_error:
	iounmap(button->v);	
remap_error:
	kfree(button);
	return ret;
}

int b_remove(struct platform_device *pdev)
{
	int i = 6;
	struct button_info *button;

	button = platform_get_drvdata(pdev);
	while(i--)
		free_irq(button[i].irq, &button[i]);
	s3c_button_exit(button);
	input_unregister_device(button->dev);
	input_free_device(button->dev);
	iounmap(button->v);	
	kfree(button);

	return 0;
}

struct platform_driver drv = {
	.driver = {
		.name = "s3c-button",
	},
	.probe = b_probe,
	.remove = b_remove,
};

static __init int module_test_init(void)
{
	return platform_driver_register(&drv);
}

static __exit void module_test_exit(void)
{
	platform_driver_unregister(&drv);
}

module_init(module_test_init);
module_exit(module_test_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Musesea");
MODULE_VERSION("1.0");
MODULE_DESCRIPTION("Test for module");

OK了!又一个驱动算是完了。

还是那句话,大家若是发现什么问题一定要告诉我,大家一起学习


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值