驱动程序实例(四):按键驱动程序(platform + input子系统 + 外部中断方式)
結(jié)合之前對Linux內(nèi)核的platform總線與input子系統(tǒng)的分析 ,本文將編寫基于platform總線和input子系統(tǒng)的Button設(shè)備的實例代碼并對其進行分析。
platform總線的分析,詳見Linux?platform驅(qū)動模型。
input子系統(tǒng)的分析,詳見Linux字符設(shè)備驅(qū)動框架(四):Linux內(nèi)核的input子系統(tǒng)。
硬件接口:
CPU:s5pv210;
Button的GPIO:GPIO_H0_2,EINT2;
LED的工作方式:按鍵彈起,低電平;按鍵按下,高電平。
1. device
在/kernel/arch/arm/mach-s5pv210/include/mach目錄下,建立一個buttons_gpio.h文件,并填充如下內(nèi)容。
#ifndef __ASM_ARCH_BUTTONSGPIO_H #define __ASM_ARCH_BUTTONSGPIO_H "buttons-gpio.h"//定義一個Button設(shè)備的數(shù)據(jù)結(jié)構(gòu) struct s5pv210_button_platdata {char *name;unsigned int gpio;unsigned int irqnum;unsigned int flags; };#endif在/kernel/arch/arm/mach-s5pv210/mach-x210.c下,添加如下內(nèi)容,并添加對buttons_gpio.h的包含。
/*Buttons*/static struct s5pv210_button_platdata s5pv210_button_pdata ={.name = "button1",.gpio = S5PV210_GPH0(2),.irqnum = IRQ_EINT2,//中斷號.flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,//上升沿觸發(fā)+下降沿觸發(fā) };static struct platform_device s5pv210_button = {.name = "s5pv210_button",.id = 1,.dev = {.platform_data = &s5pv210_button_pdata,}, };
?
將LED設(shè)備信息集成至smdkc110_devices,內(nèi)核初始化時smdkc110_devices中的設(shè)備將被注冊進內(nèi)核。
static struct platform_device *smdkc110_devices[] __initdata = {......&s5pv210_button,};
2. driver
#include <linux/kernel.h> #include <linux/init.h> #include <linux/platform_device.h> #include <linux/gpio.h> #include <linux/slab.h> #include <linux/input.h> #include <mach/buttons_gpio.h> #include <mach/hardware.h> #include <mach/regs-gpio.h> #include <mach/irqs.h> #include <linux/interrupt.h>static struct s5pv210_button_platdata *pdata; static struct input_dev *button_dev = NULL;static irqreturn_t button_interrupt(int irq, void *dummy) { int flag;s3c_gpio_cfgpin(pdata->gpio, S3C_GPIO_SFN(0x0)); //設(shè)置GPIO為input模式flag = gpio_get_value(pdata->gpio); //讀取GPIO的值s3c_gpio_cfgpin(pdata->gpio, S3C_GPIO_SFN(0x0f));//設(shè)置GPIO為eint2模式 input_report_key(button_dev, KEY_LEFT, !flag); //上報事件input_sync(button_dev); //同步事件return IRQ_HANDLED; }static int s5pv210_button_remove(struct platform_device *dev) {input_free_device(button_dev); //釋放button_dev內(nèi)存free_irq(pdata->irqnum, button_interrupt);//釋放中斷資源gpio_free(pdata->gpio); //釋放GPIOreturn 0; }static int s5pv210_button_probe(struct platform_device *dev) {int ret;pdata = dev->dev.platform_data;/*****************************申請資源******************************///申請GPIOret = gpio_request(pdata->gpio, pdata->name);if (ret) {printk(KERN_ERR "gpio_request failed, ret = %d.\n", ret);return -EBUSY;} //申請IRQif (request_irq(pdata->irqnum, button_interrupt, pdata->flags, pdata->name, NULL)) { printk(KERN_ERR "key-s5pv210.c: Can't allocate irq %d\n", pdata->irqnum);ret = -EBUSY;goto ERR_STER0;}/************************初始化GPIO資源*************************/s3c_gpio_setpull(pdata->gpio, S3C_GPIO_PULL_UP); //設(shè)置GPIO為上拉模式s3c_gpio_cfgpin(pdata->gpio, S3C_GPIO_SFN(0x0f));//設(shè)置GPIO為eint模式/*******************************創(chuàng)建接口*******************************///申請button_dev內(nèi)存空間button_dev = input_allocate_device();if(!button_dev){ret = -ENOMEM;goto ERR_STER1;}//初始化button_devset_bit(EV_KEY, button_dev->evbit); //支持EV_KEY事件set_bit(KEY_LEFT, button_dev->keybit); //支持KEY_LEFT子事件//注冊button_devif(input_register_device(button_dev) != 0){printk("s5pv210-button input register device fail!!\n");ret = -ENODEV;goto ERR_STER2;}return 0;/****************************倒映式錯誤處理****************************/ ERR_STER2:input_free_device(button_dev);ERR_STER1:free_irq(pdata->irqnum, button_interrupt);ERR_STER0:gpio_free(pdata->gpio);return ret; }//定義并初始化驅(qū)動信息 static struct platform_driver s5pv210_button_driver = {.probe = s5pv210_button_probe,.remove = s5pv210_button_remove,.driver = {.name = "s5pv210_button",.owner = THIS_MODULE,}, };//注冊驅(qū)動 static int __init s5pv210_button_init(void) {return platform_driver_register(&s5pv210_button_driver); }//注銷驅(qū)動 static void __exit s5pv210_button_exit(void) {platform_driver_unregister(&s5pv210_button_driver); }module_init(s5pv210_button_init); module_exit(s5pv210_button_exit);MODULE_AUTHOR("Lin"); MODULE_DESCRIPTION("S5PV210 BUTTON driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:s5pv210_button");3. 測試
編寫一個簡易的應(yīng)用程序,來測試上述驅(qū)動程序。
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <linux/input.h> #include <string.h>#define X210_KEY "/dev/input/event1"int main(void) {int fd = -1, ret = -1;struct input_event ev;//打開設(shè)備文件fd = open(X210_KEY, O_RDONLY);if (fd < 0){perror("open");return -1;}while (1){//讀取一個event事件包memset(&ev, 0, sizeof(struct input_event));ret = read(fd, &ev, sizeof(struct input_event));if (ret != sizeof(struct input_event)){perror("read");close(fd);return -1;}//解析event包printf("-------------------------\n");printf("type: %hd\n", ev.type);printf("code: %hd\n", ev.code);printf("value: %d\n", ev.value);printf("\n");}//關(guān)閉設(shè)備 close(fd);return 0; }?
裝載驅(qū)動模塊后,在Linux終端運行該應(yīng)用程序。在一次按鍵按下并彈起的過程中,終端中將打印出如下的信息,表明驅(qū)動程序工作正常。
-------------------------//按鍵按下 type: 1 code: 105 value: 1-------------------------//同步事件 type: 0 code: 0 value: 0-------------------------//按鍵彈起 type: 1 code: 105 value: 0-------------------------//同步事件 type: 0 code: 0 value: 0轉(zhuǎn)載于:https://www.cnblogs.com/linfeng-learning/p/9468018.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的驱动程序实例(四):按键驱动程序(platform + input子系统 + 外部中断方式)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java面试题之----get和post
- 下一篇: 分布式版本控制系统Git的安装与使用