初入android驱动开发之字符设备(五

这个字符设备系列,主要借助较容易上手的字符设备实例,去讲解linux的一些机制,以及驱动中比较常用到的中断、定时器、信号量等一些知识,由于本人自身的知识有限,对于arm的架构体系不太了解,这里,一般这里只讲,如何去用,对于一些原理性的东西不会深究,以后的文章会慢慢的加深。

想想我们当初玩51单片机的时候,那时候按键防抖是一个硬件、软件都需要处理的地方。软件一般就是加延时检测判断。当然,这里我们也可以用到定时器的这个机制,做按键驱动,这里主要还是以按键为例,,但不是讲的按键防抖。

1. 定时器的一些概念:

节拍率(HZ):它是通过静态预处理定义的,在系统启动时,按照HZ值对硬件进行设置。体系结构不同,HZ值不同。

jiffies:全局变量jiffies用来记录自系统启动以来产生的节拍的总数。启动时内核将它设为0。系统运行时间以秒为单位,等于jiffies/HZ。

定时器:它是管理内核流逝的时间的基础。内核常需要推后执行某些代码,也就是说,不在当前时间执行。定时器使用简单,一般做一些初始化工作,设置一个超时时间,指定超时发生后执行的函数,然后激活定时器就可以。指定的函数将在定时器到期时自动执行。执行结束后,定时器自行撤销。所以,定时器不断的创建和撤销,而且它的运行次数不受限制。

备注:部分neir来自于《linux内核设计与实现》

2. 驱动demo:

#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/irq.h>#include <linux/input.h>#include <linux/platform_device.h>#include <linux/miscdevice.h>#include <mach/gpio.h>#include <linux/io.h>#include <mach/hardware.h>#include <linux/delay.h>#include <asm/irq.h>#include <asm/uaccess.h>#include <linux/interrupt.h>#include <linux/gpio.h>#include <linux/wait.h>#include <linux/sched.h>#include <plat/gpio-core.h>#include <plat/gpio-cfg.h>#include <plat/gpio-cfg-helpers.h>static struct class *buttondrv_class;static struct device *buttondrv_class_dev;int major;volatile unsigned long *GPCCON;volatile unsigned long *GPCDAT;//static DECLARE_WAIT_QUEUE_HEAD(button_waitq);static struct timer_list button_timer;static unsigned char key_val;static volatile int ev_press = 0;struct pin_desc{unsigned int pin;unsigned int key_val;};struct pin_desc pins_desc[2] = {{S5PV210_GPH3(7), 0x01},};struct pins_desc *irq_temp;static irqreturn_t buttons_irq(int irq, void *dev_id){printk(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>buttons_irq\n");irq_temp = (struct pin_desc *)dev_id;mod_timer(&button_timer, jiffies+HZ/100);return IRQ_RETVAL(IRQ_HANDLED);}static int button_drv_open(struct inode *inode, struct file *file){printk(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>button_drv_open\n");int ret=-1;s3c_gpio_setpull(S5PV210_GPH3(7), S3C_GPIO_PULL_NONE);ret = request_threaded_irq(gpio_to_irq(S5PV210_GPH3(7)), NULL,buttons_irq,IRQF_TRIGGER_RISING,"s2", &pins_desc[0]);printk("ret=%d irq=%d >>>>>>>>>>>>>>>>>>>>>>>>>\n ",ret,gpio_to_irq(S5PV210_GPH3(7)));return 0;}int button_drv_close(struct inode *inode, struct file *file){free_irq(gpio_to_irq(S5PV210_GPH3(7)), &pins_desc[0]);return 0;}static int button_drv_read(struct file *filp, char __user *buf,size_t count, loff_t *offp){printk(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>button_drv_read\n");if (count != 1)return -EINVAL;//wait_event_interruptible(button_waitq, ev_press);copy_to_user(buf, &key_val, 1);key_val=0;ev_press = 0;return 1;}static void button_timer_function(unsigned long data){printk(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>button_timer_function\n");struct pin_desc *pindesc = irq_temp;unsigned int pinval;pinval = gpio_get_value(pindesc->pin);printk("irq >>>>>>>>>>>>>>>>>>>>>>>>>>>>pinval =%d \n",pinval);if (pinval){key_val = 0x80 | pindesc->key_val;}else{key_val = pindesc->key_val;}ev_press = 1;// wake_up_interruptible(&button_waitq); }static struct file_operations button_drv_fops = {.owner = THIS_MODULE,.open = button_drv_open,.read=button_drv_read,.release = button_drv_close,};unsigned long test=0;static int button_drv_init(void){printk(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>button_drv_init\n");button_timer.function = button_timer_function;button_timer.data=test;init_timer(&button_timer);add_timer(&button_timer); //setup_timer(&button_timer,button_timer_function,test); //before 4 method instead of the oneGPCCON = (volatile unsigned long *)ioremap(0xE0200C60, 8); GPCDAT= GPCCON + 1;if (!GPCCON) {return -EIO;}major = register_chrdev(0, "button_drv", &button_drv_fops); buttondrv_class = class_create(THIS_MODULE, "buttondrv");buttondrv_class_dev = device_create(buttondrv_class, NULL, MKDEV(major, 0), NULL, "button"); return 0;}static void button_drv_exit(void){printk(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>button_drv_exit\n");unregister_chrdev(major, "button_drv"); device_unregister(buttondrv_class_dev);class_destroy(buttondrv_class);iounmap(GPCCON);}module_init(button_drv_init);module_exit(button_drv_exit);MODULE_LICENSE("GPL");

2.1 代码简单解析:

定时器操作的步骤:

1.定义一个timer_list结构体:static struct timer_list button_timer;

2.定时器超时调用的函数:button_timer.function = button_timer_function;

给定时器操作函数传的参数:button_timer.data=test;

根据该定义该timer_list的参数初始化定时器:init_timer(&button_timer);

激活定时器:add_timer(&button_timer);

注:setup_timer(&button_timer,button_timer_function,test); 这个可代替上面的2步。

3. 在中断处理函数中,mod_timer(&button_timer, jiffies+HZ/100); //10ms

注:动态定时器不需要手动释放,mod_timer超时执行之后,就会自动释放。

版权声明:本文为博主原创文章,未经博主允许不得转载。

风景如何,其实并不重要。重要的是,你在我的身边。

初入android驱动开发之字符设备(五

相关文章:

你感兴趣的文章:

标签云: