700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 驱动程序实例(四):按键驱动程序(platform + input子系统 + 外部中断方式)

驱动程序实例(四):按键驱动程序(platform + input子系统 + 外部中断方式)

时间:2019-03-01 04:37:04

相关推荐

驱动程序实例(四):按键驱动程序(platform + input子系统 + 外部中断方式)

结合之前对Linux内核的platform总线与input子系统的分析 ,本文将编写基于platform总线和input子系统的Button设备的实例代码并对其进行分析。

platform总线的分析,详见Linuxplatform驱动模型。

input子系统的分析,详见Linux字符设备驱动框架(四):Linux内核的input子系统。

硬件接口:

CPU:s5pv210;

Button的GPIO:GPIO_H0_2,EINT2;

LED的工作方式:按键弹起,低电平;按键按下,高电平。

1. device

在/kernel/arch/arm/mach-s5pv210/include/mach目录下,建立一个buttons_gpio.h文件,并填充如下内容。

#ifndef __ASM_ARCH_BUTTONSGPIO_H#define __ASM_ARCH_BUTTONSGPIO_H "buttons-gpio.h"//定义一个Button设备的数据结构struct s5pv210_button_platdata {char *name;unsigned int gpio;unsigned int irqnum;unsigned int flags;};#endif

在/kernel/arch/arm/mach-s5pv210/mach-x210.c下,添加如下内容,并添加对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,//上升沿触发+下降沿触发};static struct platform_device s5pv210_button = {.name = "s5pv210_button",.id= 1,.dev = {.platform_data = &s5pv210_button_pdata,},};

将LED设备信息集成至smdkc110_devices,内核初始化时smdkc110_devices中的设备将被注册进内核。

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)); //设置GPIO为input模式flag = gpio_get_value(pdata->gpio); //读取GPIO的值s3c_gpio_cfgpin(pdata->gpio, S3C_GPIO_SFN(0x0f));//设置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内存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); //设置GPIO为上拉模式s3c_gpio_cfgpin(pdata->gpio, S3C_GPIO_SFN(0x0f));//设置GPIO为eint模式/*******************************创建接口*******************************///申请button_dev内存空间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;}//定义并初始化驱动信息static struct platform_driver s5pv210_button_driver = {.probe = s5pv210_button_probe,.remove = s5pv210_button_remove,.driver = {.name = "s5pv210_button",.owner = THIS_MODULE,},};//注册驱动static int __init s5pv210_button_init(void){return platform_driver_register(&s5pv210_button_driver);}//注销驱动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. 测试

编写一个简易的应用程序,来测试上述驱动程序。

#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;//打开设备文件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");}//关闭设备 close(fd);return 0;}

装载驱动模块后,在Linux终端运行该应用程序。在一次按键按下并弹起的过程中,终端中将打印出如下的信息,表明驱动程序工作正常。

-------------------------//按键按下type: 1code: 105value: 1-------------------------//同步事件type: 0code: 0value: 0-------------------------//按键弹起type: 1code: 105value: 0-------------------------//同步事件type: 0code: 0value: 0

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。