天天看點

驅動程式之_1_字元裝置_9_輸入子系統_2_執行個體

驅動程式之驅動程式之_1_字元裝置_9_輸入子系統_2_執行個體

本文中input_handler層使用evdev,在input_dev層編寫按鍵執行個體

基本流程:

1、編寫入口函數,配置設定、設定、注冊input_dev結構體,并且完成硬體初始化

2、編寫出口函數,完成與入口函數相反的操作

3、聲明、定義硬體相關結構體和定時器

4、編寫按鍵中斷服務程式

5、編寫定時器中斷服務程式,定時時間為10ms,用于消抖

6、添加相關頭檔案

附上完整代碼

#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/irq.h>
#include <linux/gpio_keys.h>
#include <asm/gpio.h>

/* 結構體的聲明和定義 */
typedef struct{
	unsigned char *pucDevName;
	int 		   dwIrq;
	unsigned long  dwIrqFlags;
	unsigned int   dwPin;
	unsigned int   dwVal;
}buttons_desc, *pbuttons_desc;

buttons_desc g_tButtonsDesc[4] = 
{
{"S2",IRQ_EINT0, IRQT_BOTHEDGE,S3C2410_GPF0 ,KEY_L},
{"S3",IRQ_EINT2, IRQT_BOTHEDGE,S3C2410_GPF2 ,KEY_S},
{"S4",IRQ_EINT11,IRQT_BOTHEDGE,S3C2410_GPG3 ,KEY_ENTER},
{"S5",IRQ_EINT19,IRQT_BOTHEDGE,S3C2410_GPG11,KEY_LEFTSHIFT},
};

static struct input_dev *g_ptButtonsDev;
static struct timer_list g_tButtonsTimer;
static pbuttons_desc g_ptButtonsDescSelect;

/* 定時器中斷服務程式 */
static void buttons_timer_isr(unsigned long data)
{
	pbuttons_desc	g_ptButtonsDescTmp = g_ptButtonsDescSelect;
	if(!g_ptButtonsDescTmp)
		return ;

	if(s3c2410_gpio_getpin(g_ptButtonsDescTmp->dwPin))	//松開
	{
		input_event(g_ptButtonsDev,EV_KEY,g_ptButtonsDescTmp->dwVal,0);
		input_sync(g_ptButtonsDev);
	}
	else
	{
		input_event(g_ptButtonsDev,EV_KEY,g_ptButtonsDescTmp->dwVal,1);
		input_sync(g_ptButtonsDev);		
	}
}

/* 按鍵中斷服務程式 */
static irqreturn_t buttons_isr(int irq, void *dev_id)
{
	g_ptButtonsDescSelect = (pbuttons_desc)dev_id;
	mod_timer(&g_tButtonsTimer, jiffies + HZ / 100);	
	return IRQ_RETVAL(IRQ_HANDLED);
}

/* 入口函數 */
static int input_init(void)
{
	int i;
	int iError;
	
	/* 配置設定設定注冊結構體 */
	g_ptButtonsDev = input_allocate_device();

	set_bit(EV_KEY,       g_ptButtonsDev->evbit); 
	set_bit(EV_REP,       g_ptButtonsDev->evbit); 	
	
	set_bit(KEY_L,        g_ptButtonsDev->keybit); 	
	set_bit(KEY_S,        g_ptButtonsDev->keybit); 	
	set_bit(KEY_LEFTSHIFT,g_ptButtonsDev->keybit); 	
	set_bit(KEY_ENTER,    g_ptButtonsDev->keybit); 	

	input_register_device(g_ptButtonsDev);

	/* 建立定時器并設定其中斷服務程式 */
	init_timer(&g_tButtonsTimer);
	g_tButtonsTimer.function = buttons_timer_isr;
	add_timer(&g_tButtonsTimer);

	/* 設定按鍵中斷 */
	for(i = 0;i < 4;i++)
		iError = request_irq(g_tButtonsDesc[i].dwIrq,buttons_isr,g_tButtonsDesc[i].dwIrqFlags,
									g_tButtonsDesc[i].pucDevName,&g_tButtonsDesc[i]);

	return 0;
}

/* 出口函數 */
static void input_exit(void)
{
	int i;
	
	/* 關閉按鍵中斷 */
	for(i = 0;i < 4;i++)
		free_irq(g_tButtonsDesc[i].dwIrq,&g_tButtonsDesc[i]);

	/* 銷毀定時器 */
	del_timer(&g_tButtonsTimer);

	/* 銷毀結構體 */
	input_unregister_device(g_ptButtonsDev);
}

module_init(input_init);
module_exit(input_exit);

MODULE_LICENSE("GPL");
           

測試方法:

cat /dev/event*

加載驅動裝置,再次cat /dev/event*,會多出一個event

1、hexdump /dev/event1(event1是加載驅動裝置後新出現的event,根據實際情況修改),按下按鍵會回顯按鍵事件的時間、鍵值碼、類型等資訊

2、cat /dev/tty1,按下字母按鍵,再按下回車按鍵,會回顯字母資訊,由于使能了REP事件,是以按鍵長按有效

3、exec 0</dev/tty1,按下’l’,‘s’,再按下"enter",這時不僅回顯資訊,并且按鍵傳入控制台,效果相當于鍵盤輸入"ls"