1. 程式人生 > >驅動之路三--------button驅動(input裝置)

驅動之路三--------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了!又一個驅動算是完了。

還是那句話,大家若是發現什麼問題一定要告訴我,大家一起學習