定时器防抖动
2016-05-18 22:30
295 查看
/*功能:使用定时器防抖动
*2016年5月14日20:35:13
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <linux/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
static struct class *seventhdrv_class;
static struct class_device *seventhdrv_class_devs[4];
volatile unsigned long * gpfcon;
volatile unsigned long * gpfdat;
volatile unsigned long * gpgcon;
volatile unsigned long * gpgdat;
/*
*
确定按键值 s3c2410_gpio_getpin
*/
struct pin_desc{
unsigned int pin;
unsigned int key_val;
};
/*键值:按下时:0x01,0x02,0x03x0x04*/
/*键值:松开时:0x81,0x82,0x83,0x84*/
struct pin_desc pins_desc[4] = {
{S3C2410_GPF0,0x01},
{S3C2410_GPF2,0x01},
{S3C2410_GPG3,0x01},
{S3C2410_GPG11,0x01},
};
/*发生中断时的引脚描述*/
static struct pin_desc * irq_pd;
/*定义定时器结构体*/
static struct timer_list buttons_timer;
static unsigned char key_val;
//static int canopen = 1; 对应open函数中if方法
//atomic_t canopen = ATOMIC_INIT(1); //定义原子变量v并初始化为0
static DECLARE_MUTEX(button_lock); // 定义一个名称为button_lock的信号量,并将信号量初始化为1 。定义互斥锁
static struct fasync_struct *button_async;
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
/* 中断事件标志, 中断服务程序将它置1,seventh_drv_read将它清0 */
static volatile int ev_press = 0;
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
/* 记录下引脚描述 */
irq_pd = (struct pin_desc *)dev_id;
/* 10ms后启动定时器 ,定时器其实是在定时器链表中存放的,
每一个时钟中断都会检查链表中的哪个定时器时间到了,并执行相应的定时器处理函数*/
/*修改定时器的超时时间expires*/
mod_timer(&buttons_timer, jiffies+HZ/100);//HZ可以将理解为1秒
/*闹钟什么时候到,是基于jiffies这个值的,这个值是个全局变量,这个值每隔十毫秒就会有个系统时钟中断
在系统时钟中断里面,jiffies这个值就会累加 HZ是用来定义每一秒有几次timer interrupts。
Jiffies为Linux核心变数(unsigned long),它被用来记录系统自开机以来,已经过了多少tick。每发生一次
timer interrupt,Jiffies变数会被加一*/
/*
LINUX系统时钟频率是一个常数HZ来决定的,通常HZ=100,那么他的精度度就是10ms
(毫秒)。也就是说每10ms一次中断。所以一般来说Linux的精确度是10毫秒
*/
return IRQ_HANDLED;
}
static int seventh_drv_open(struct inode * inode, struct file * file)
{
#if 0
/*第一次执行open函数时,--canopen!=0不成立,所以执行if后面的函数
从第二次以后 --canopen!=0 都成立,所以会返回错误,即表示不能第二次打开
该方法有BUG,因为linux是多任务操作系统,在 执行--canopen != 0期间的取值时,
cpu可能会被切换出去,去执行另一个程序打开open函数后,再返回继续执行--canopen != 0
接下来的程序,结果是两个应用程序都成功打开了设备*/.
if(--canopen != 0)
{
canopen ++;
return -EBUSY;
}
#endif
/*获取信号量,如果是第一次执行open函数的话,就可以获得信号量,当第二个程序在执行open函数时,就无法获得信号量,
就会进入不可中断的休眠状态,只有第一个应用程序把button_lock这个信号量释放的时候,第二个应用程序才会被唤醒
继续执行。
down系列函数会使信号量的值减1
up会使信号量的值加1
调用down的进程不允许被中断,*/
/*对open函数传入的O_NONBLOCK标志位的处理,在file这个结构体中,这个结构是内核给我们提供的*/
if(file->f_flags & O_NONBLOCK)
{
/*如果打不开这个设备就会立刻返回错误*/
if(down_trylock(&button_lock))
return -EBUSY;
}
else
{
down(&button_lock);
}
#if 0
/*
int atomic_dec_and_test(atomic_t *v); //自减操作后测试其是否为0,为0则返回true,否则返回false。
atomic_t v = ATOMIC_INIT(0); //定义原子变量v并初始化为0
atomic_read(atomic_t *v); //返回原子变量的值
void atomic_inc(atomic_t *v); //原子变量增加1
void atomic_dec(atomic_t *v); //原子变量减少1
*/
if(!atomic_dec_and_test(&canopen)) /*被执行过一次之后,canopen变为0*/
{
atomic_inc(&canopen);
return -EBUSY;
}
#endif
/*配置GPF0,2 位输入引脚 */
/*配置GPG3,11为输入引脚 */
/*
IRQ_EINT0是在irqs.h中定义的
IRQT_BOTHEDGE是在s3c_irqext_type函数中找到,在irq.h中定义
*/
//向内核注册中断处理函数
request_irq(IRQ_EINT0,buttons_irq,IRQT_BOTHEDGE,"s2",&pins_desc[0]);
request_irq(IRQ_EINT2,buttons_irq,IRQT_BOTHEDGE,"s3",&pins_desc[1]);
request_irq(IRQ_EINT11,buttons_irq,IRQT_BOTHEDGE,"s4",&pins_desc[2]);
request_irq(IRQ_EINT19,buttons_irq,IRQT_BOTHEDGE,"s5",&pins_desc[3]);
return 0;
}
/*函数的参数是用户空间的函数的参数*/
static ssize_t seventh_drv_read(struct file *file, const __user char *buffer,size_t count, loff_t *ppos)
{
if(count != 1)
return -EINVAL;//返回错误值
if (file->f_flags & O_NONBLOCK)
{
/*判断有没有按键按下,没有按键按下的话*/
if (!ev_press)
return -EAGAIN;/*如果你连续做read操作而没有数据可读。此时程序不会阻塞起来等待数据准备就绪返回,
read函数会返回一个错误EAGAIN,提示你的应用程序现在没有数据可读请稍后再试,再次执行*/
}
else
{
/*如果没有按键按下:进入休眠(让出CPU,不返回)*/
wait_event_interruptible(button_waitq,ev_press);
}
/*如果休眠的程序被唤醒,则会从wait_event_interruptible继续往下执行*/
/*如果有按键动作发生,则直接返回键值*/
copy_to_user(buffer ,&key_val,1);
ev_press = 0;
return 1;
}
static void buttons_timer_function(unsigned long data)
{
/*利用设备号来传递引脚号和值*/
struct pin_desc * pindesc = irq_pd;
unsigned int pinval ;
if(!pindesc)
return;
pinval = s3c2410_gpio_getpin(pindesc->pin);//系统提供的读取引脚状态的函数
if(pinval)
{
/*按键松开*/
key_val = 0x80 | pindesc->key_val;
}
else
{
/*按键按下*/
key_val = pindesc->key_val;
}
ev_press = 1; /* 表示中断发生了 */
/*由kill_fasync函数发出SIGIO信号,发给谁,是在button_async这个结构中定义的
button_async这个结构要在seventh_drv_fasync函数中进行初始化
在内核里面一般向应用程序发出的是SIGIO信号,表示有数据可供读写*/
*/
kill_fasync(&button_async, SIGIO, POLL_IN);
wake_up_interruptible(&button_waitq); /* 唤醒休眠的进程 */
}
/*入口函数*/
int major;
static int seventh_drv_init (void)
{
/*初始化定时器,没有设置超时时间,则超时时间就是0*/
init_timer(&buttons_timer);
buttons_timer.function = buttons_timer_function;
/*告诉内核,启动定时器,当定时器的超时时间一到就会调用buttons_timer_function*/
/*当启动定时器到达第一个时钟中断时,jiffies>=0,则会立刻调用定时器处理函数,此时还没有按键产生,则要在
定时器处理函数中判断一下是否有中断*/
add_timer(&buttons_timer);
major = register_chrdev(0,"secod_drv",&seventh_drv_fops);
seventhdrv_class = class_create(THIS_MODULE, "secod_drv");//创建个类
seventhdrv_class_devs = class_device_create(seventhdrv_class, NULL, MKDEV(major, 0), NULL, "buttons"); /* /dev/buttons */
gpfcon = (volatile unsigned long *)ioremap(0x56000050,16);
gpfdat = gpfcon + 1;//指向0x56000054
gpgcon = (volatile unsigned long *)ioremap(0x56000060,16);
gpgdat = gpgcon + 1;//指向0x56000064
return 0;
}
/*出口函数*/
int major;
static int seventh_drv_exit (void)
{
unregister_chrdev(major,"secod_drv");
class_device_unregister(seventhdrv_class_devs);
class_destroy(seventhdrv_class);
iounmap(gpfcon);
iounmap(gpgcon);
return 0;
}
int seventh_drv_close (struct inode * inode, struct file * file)
{
/* canopen ++;是配合只能一次打开open函数?当open函数真正被打开后,
canopen的值为0,此时不能在被任何应用程序打开,当打开的open函数被关闭时canopen
的值变为1,以便下次再被应用程序打开*/
//canopen ++; 对应于open函数中的if语句
//atomic_inc(&canopen);
free_irq(IRQ_EINT0,&pins_desc[0]);
free_irq(IRQ_EINT2,&pins_desc[1]);
free_irq(IRQ_EINT11,&pins_desc[2]);
free_irq(IRQ_EINT19,&pins_desc[3]);
up(&button_lock);/*第一个程序运行完后,释放掉信号量*/
return 0;
}
/*如果seventh_drv_poll函数返回的是0,则当前进程会进入休眠状态,直到超时被唤醒,返回到用户态,
用户态的poll函数返回0,或者是seventh_drv_poll函数返回非0,返回到用户态*/
static unsigned int seventh_drv_poll(struct file *file, poll_table *wait)
{
unsigned int mask = 0;
/*poll_wait函数是将当前进程挂到button_waitq队列中,不会使当前进程立即进入休眠
使当前进程进入休眠是在其他的内核中的函数中实现的*/
poll_wait(file, &button_waitq, wait); // 不会立即休眠
if (ev_press)
mask |= POLLIN | POLLRDNORM;
return mask;
}
f_owner
static int seventh_drv_fasync (int fd, struct file *filp, int on)
{
printk("driver: seventh_drv_fasync\n");
/*
fasync_helper函数初始化button_async这个结构体,初始化后,
kill_fasync(&button_async, SIGIO, POLL_IN);这个函数就能给应用程序发送信号了
*/
return fasync_helper (fd, filp, on, &button_async);
}
static struct file_operations seventh_drv_fops = {
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open = seventh_drv_open, //表示将first_drv_open函数的地址赋给file_operations结构体中open函数,
.read =
seventh_drv_read, //以后执行 first_drv_open函数时会自动调用file_operations结构体中的open函数
.release = seventh_drv_close,//关闭设备的时候,释放open函数中注册中断处理函数的irq
.poll = seventh_drv_poll,
.fasync = seventh_drv_fasync,
};
/*修饰*/
modules_init(seventh_drv_init);
modules_exit(seventh_drv_exit);
MODULE_LICENSE("GPL");
//测试函数
/*功能:使用定时器防抖动
2016年5月14日20:35:35*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
/*
阻塞操作
是指在执行设备操作时若不能获得资源则挂起进程,直到满足可操作的条件后再进行操作
被挂起的进程进入休眠状态,被从调度器的运行队列移走,直到等待的条件被满足
非阻塞操作
进程在不能进行设备操作时并不挂起,它或者放弃,或者不停地查询,直至可以进行操作.
*/
/* sixthdrvtest
*/
int fd;
void my_signal_fun(int signum)
{
unsigned char key_val;
read(fd, &key_val, 1);
printf("key_val: 0x%x\n", key_val);
}
int main(int argc, char **argv)
{
unsigned char key_val;
int ret;
int Oflags;
/*使用signal系统调用给SIGIO这个信号挂接处理函数
在内核里面一般向应用程序发出的是SIGIO信号*/
signal(SIGIO, my_signal_fun);
/*默认为非阻塞 */
fd = open("/dev/buttons", O_RDWR );
if (fd < 0)
{
printf("can't open!\n");
return -1;
}
#if 0
/*buttons这个设备就是驱动程序*/
/*F_GETFL :读取文件状态标志。*/
/*可以用fcntl 函数改变一个已打开的文件的属性,可以重新设置读、写、追加、非阻塞等标志*/
/*F_SETFL 将文件状态标志设置为第三个参数的值 (取为整型值)。*/
/* fcntl的F_SETOWN指令设置当前进程为设备文件owner*/
<
9b8a
br />
/* fcntl(fd, F_SETOWN, getpid());告诉驱动程序当前PID进程号
*/
fcntl(fd, F_SETOWN, getpid());
/*读取fd的文件状态标志位*/
Oflags = fcntl(fd, F_GETFL);
/*
设置fd的文件状态标志位为Oflags | FASYNC 即异步通知
调用fcntl(fd, F_SETFL, Oflags | FASYNC);函数时,会进入驱动程序的file_operations结构体执行fasync函数
*/
/*
每当FASYNC标志改变时,驱动程序中的fasync()函数将得以执行。
驱动中应该实现fasync()函数。
*/
fcntl(fd, F_SETFL, Oflags | FASYNC);
#endif
while (1)
{
/*判断返回值,非阻塞的话一读就会返回一个值,*/
ret = read(fd, &key_val, 1);
printf("key_val: 0x%x, ret = %d\n", key_val, ret);
}
return 0;
}
/*
fcnt1函数返回值说明
返回说明:
成功执行时,对于不同的操作,有不同的返回值
F_DUPFD: 新文件描述词
F_GETFD: 标志值
F_GETFL: 标志值
F_GETOWN: 文件描述词属主
F_GETSIG: 读写变得可行时将要发送的通告信号,或者0对于传统的SIGIO行为
*/
/*
getpid()用来取得目前进程的进程识别码,许多程序利用取到的
此值来建立临时文件,以避免临时文件相同带来的问题。*/
*2016年5月14日20:35:13
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <linux/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
static struct class *seventhdrv_class;
static struct class_device *seventhdrv_class_devs[4];
volatile unsigned long * gpfcon;
volatile unsigned long * gpfdat;
volatile unsigned long * gpgcon;
volatile unsigned long * gpgdat;
/*
*
确定按键值 s3c2410_gpio_getpin
*/
struct pin_desc{
unsigned int pin;
unsigned int key_val;
};
/*键值:按下时:0x01,0x02,0x03x0x04*/
/*键值:松开时:0x81,0x82,0x83,0x84*/
struct pin_desc pins_desc[4] = {
{S3C2410_GPF0,0x01},
{S3C2410_GPF2,0x01},
{S3C2410_GPG3,0x01},
{S3C2410_GPG11,0x01},
};
/*发生中断时的引脚描述*/
static struct pin_desc * irq_pd;
/*定义定时器结构体*/
static struct timer_list buttons_timer;
static unsigned char key_val;
//static int canopen = 1; 对应open函数中if方法
//atomic_t canopen = ATOMIC_INIT(1); //定义原子变量v并初始化为0
static DECLARE_MUTEX(button_lock); // 定义一个名称为button_lock的信号量,并将信号量初始化为1 。定义互斥锁
static struct fasync_struct *button_async;
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
/* 中断事件标志, 中断服务程序将它置1,seventh_drv_read将它清0 */
static volatile int ev_press = 0;
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
/* 记录下引脚描述 */
irq_pd = (struct pin_desc *)dev_id;
/* 10ms后启动定时器 ,定时器其实是在定时器链表中存放的,
每一个时钟中断都会检查链表中的哪个定时器时间到了,并执行相应的定时器处理函数*/
/*修改定时器的超时时间expires*/
mod_timer(&buttons_timer, jiffies+HZ/100);//HZ可以将理解为1秒
/*闹钟什么时候到,是基于jiffies这个值的,这个值是个全局变量,这个值每隔十毫秒就会有个系统时钟中断
在系统时钟中断里面,jiffies这个值就会累加 HZ是用来定义每一秒有几次timer interrupts。
Jiffies为Linux核心变数(unsigned long),它被用来记录系统自开机以来,已经过了多少tick。每发生一次
timer interrupt,Jiffies变数会被加一*/
/*
LINUX系统时钟频率是一个常数HZ来决定的,通常HZ=100,那么他的精度度就是10ms
(毫秒)。也就是说每10ms一次中断。所以一般来说Linux的精确度是10毫秒
*/
return IRQ_HANDLED;
}
static int seventh_drv_open(struct inode * inode, struct file * file)
{
#if 0
/*第一次执行open函数时,--canopen!=0不成立,所以执行if后面的函数
从第二次以后 --canopen!=0 都成立,所以会返回错误,即表示不能第二次打开
该方法有BUG,因为linux是多任务操作系统,在 执行--canopen != 0期间的取值时,
cpu可能会被切换出去,去执行另一个程序打开open函数后,再返回继续执行--canopen != 0
接下来的程序,结果是两个应用程序都成功打开了设备*/.
if(--canopen != 0)
{
canopen ++;
return -EBUSY;
}
#endif
/*获取信号量,如果是第一次执行open函数的话,就可以获得信号量,当第二个程序在执行open函数时,就无法获得信号量,
就会进入不可中断的休眠状态,只有第一个应用程序把button_lock这个信号量释放的时候,第二个应用程序才会被唤醒
继续执行。
down系列函数会使信号量的值减1
up会使信号量的值加1
调用down的进程不允许被中断,*/
/*对open函数传入的O_NONBLOCK标志位的处理,在file这个结构体中,这个结构是内核给我们提供的*/
if(file->f_flags & O_NONBLOCK)
{
/*如果打不开这个设备就会立刻返回错误*/
if(down_trylock(&button_lock))
return -EBUSY;
}
else
{
down(&button_lock);
}
#if 0
/*
int atomic_dec_and_test(atomic_t *v); //自减操作后测试其是否为0,为0则返回true,否则返回false。
atomic_t v = ATOMIC_INIT(0); //定义原子变量v并初始化为0
atomic_read(atomic_t *v); //返回原子变量的值
void atomic_inc(atomic_t *v); //原子变量增加1
void atomic_dec(atomic_t *v); //原子变量减少1
*/
if(!atomic_dec_and_test(&canopen)) /*被执行过一次之后,canopen变为0*/
{
atomic_inc(&canopen);
return -EBUSY;
}
#endif
/*配置GPF0,2 位输入引脚 */
/*配置GPG3,11为输入引脚 */
/*
IRQ_EINT0是在irqs.h中定义的
IRQT_BOTHEDGE是在s3c_irqext_type函数中找到,在irq.h中定义
*/
//向内核注册中断处理函数
request_irq(IRQ_EINT0,buttons_irq,IRQT_BOTHEDGE,"s2",&pins_desc[0]);
request_irq(IRQ_EINT2,buttons_irq,IRQT_BOTHEDGE,"s3",&pins_desc[1]);
request_irq(IRQ_EINT11,buttons_irq,IRQT_BOTHEDGE,"s4",&pins_desc[2]);
request_irq(IRQ_EINT19,buttons_irq,IRQT_BOTHEDGE,"s5",&pins_desc[3]);
return 0;
}
/*函数的参数是用户空间的函数的参数*/
static ssize_t seventh_drv_read(struct file *file, const __user char *buffer,size_t count, loff_t *ppos)
{
if(count != 1)
return -EINVAL;//返回错误值
if (file->f_flags & O_NONBLOCK)
{
/*判断有没有按键按下,没有按键按下的话*/
if (!ev_press)
return -EAGAIN;/*如果你连续做read操作而没有数据可读。此时程序不会阻塞起来等待数据准备就绪返回,
read函数会返回一个错误EAGAIN,提示你的应用程序现在没有数据可读请稍后再试,再次执行*/
}
else
{
/*如果没有按键按下:进入休眠(让出CPU,不返回)*/
wait_event_interruptible(button_waitq,ev_press);
}
/*如果休眠的程序被唤醒,则会从wait_event_interruptible继续往下执行*/
/*如果有按键动作发生,则直接返回键值*/
copy_to_user(buffer ,&key_val,1);
ev_press = 0;
return 1;
}
static void buttons_timer_function(unsigned long data)
{
/*利用设备号来传递引脚号和值*/
struct pin_desc * pindesc = irq_pd;
unsigned int pinval ;
if(!pindesc)
return;
pinval = s3c2410_gpio_getpin(pindesc->pin);//系统提供的读取引脚状态的函数
if(pinval)
{
/*按键松开*/
key_val = 0x80 | pindesc->key_val;
}
else
{
/*按键按下*/
key_val = pindesc->key_val;
}
ev_press = 1; /* 表示中断发生了 */
/*由kill_fasync函数发出SIGIO信号,发给谁,是在button_async这个结构中定义的
button_async这个结构要在seventh_drv_fasync函数中进行初始化
在内核里面一般向应用程序发出的是SIGIO信号,表示有数据可供读写*/
*/
kill_fasync(&button_async, SIGIO, POLL_IN);
wake_up_interruptible(&button_waitq); /* 唤醒休眠的进程 */
}
/*入口函数*/
int major;
static int seventh_drv_init (void)
{
/*初始化定时器,没有设置超时时间,则超时时间就是0*/
init_timer(&buttons_timer);
buttons_timer.function = buttons_timer_function;
/*告诉内核,启动定时器,当定时器的超时时间一到就会调用buttons_timer_function*/
/*当启动定时器到达第一个时钟中断时,jiffies>=0,则会立刻调用定时器处理函数,此时还没有按键产生,则要在
定时器处理函数中判断一下是否有中断*/
add_timer(&buttons_timer);
major = register_chrdev(0,"secod_drv",&seventh_drv_fops);
seventhdrv_class = class_create(THIS_MODULE, "secod_drv");//创建个类
seventhdrv_class_devs = class_device_create(seventhdrv_class, NULL, MKDEV(major, 0), NULL, "buttons"); /* /dev/buttons */
gpfcon = (volatile unsigned long *)ioremap(0x56000050,16);
gpfdat = gpfcon + 1;//指向0x56000054
gpgcon = (volatile unsigned long *)ioremap(0x56000060,16);
gpgdat = gpgcon + 1;//指向0x56000064
return 0;
}
/*出口函数*/
int major;
static int seventh_drv_exit (void)
{
unregister_chrdev(major,"secod_drv");
class_device_unregister(seventhdrv_class_devs);
class_destroy(seventhdrv_class);
iounmap(gpfcon);
iounmap(gpgcon);
return 0;
}
int seventh_drv_close (struct inode * inode, struct file * file)
{
/* canopen ++;是配合只能一次打开open函数?当open函数真正被打开后,
canopen的值为0,此时不能在被任何应用程序打开,当打开的open函数被关闭时canopen
的值变为1,以便下次再被应用程序打开*/
//canopen ++; 对应于open函数中的if语句
//atomic_inc(&canopen);
free_irq(IRQ_EINT0,&pins_desc[0]);
free_irq(IRQ_EINT2,&pins_desc[1]);
free_irq(IRQ_EINT11,&pins_desc[2]);
free_irq(IRQ_EINT19,&pins_desc[3]);
up(&button_lock);/*第一个程序运行完后,释放掉信号量*/
return 0;
}
/*如果seventh_drv_poll函数返回的是0,则当前进程会进入休眠状态,直到超时被唤醒,返回到用户态,
用户态的poll函数返回0,或者是seventh_drv_poll函数返回非0,返回到用户态*/
static unsigned int seventh_drv_poll(struct file *file, poll_table *wait)
{
unsigned int mask = 0;
/*poll_wait函数是将当前进程挂到button_waitq队列中,不会使当前进程立即进入休眠
使当前进程进入休眠是在其他的内核中的函数中实现的*/
poll_wait(file, &button_waitq, wait); // 不会立即休眠
if (ev_press)
mask |= POLLIN | POLLRDNORM;
return mask;
}
f_owner
static int seventh_drv_fasync (int fd, struct file *filp, int on)
{
printk("driver: seventh_drv_fasync\n");
/*
fasync_helper函数初始化button_async这个结构体,初始化后,
kill_fasync(&button_async, SIGIO, POLL_IN);这个函数就能给应用程序发送信号了
*/
return fasync_helper (fd, filp, on, &button_async);
}
static struct file_operations seventh_drv_fops = {
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open = seventh_drv_open, //表示将first_drv_open函数的地址赋给file_operations结构体中open函数,
.read =
seventh_drv_read, //以后执行 first_drv_open函数时会自动调用file_operations结构体中的open函数
.release = seventh_drv_close,//关闭设备的时候,释放open函数中注册中断处理函数的irq
.poll = seventh_drv_poll,
.fasync = seventh_drv_fasync,
};
/*修饰*/
modules_init(seventh_drv_init);
modules_exit(seventh_drv_exit);
MODULE_LICENSE("GPL");
//测试函数
/*功能:使用定时器防抖动
2016年5月14日20:35:35*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
/*
阻塞操作
是指在执行设备操作时若不能获得资源则挂起进程,直到满足可操作的条件后再进行操作
被挂起的进程进入休眠状态,被从调度器的运行队列移走,直到等待的条件被满足
非阻塞操作
进程在不能进行设备操作时并不挂起,它或者放弃,或者不停地查询,直至可以进行操作.
*/
/* sixthdrvtest
*/
int fd;
void my_signal_fun(int signum)
{
unsigned char key_val;
read(fd, &key_val, 1);
printf("key_val: 0x%x\n", key_val);
}
int main(int argc, char **argv)
{
unsigned char key_val;
int ret;
int Oflags;
/*使用signal系统调用给SIGIO这个信号挂接处理函数
在内核里面一般向应用程序发出的是SIGIO信号*/
signal(SIGIO, my_signal_fun);
/*默认为非阻塞 */
fd = open("/dev/buttons", O_RDWR );
if (fd < 0)
{
printf("can't open!\n");
return -1;
}
#if 0
/*buttons这个设备就是驱动程序*/
/*F_GETFL :读取文件状态标志。*/
/*可以用fcntl 函数改变一个已打开的文件的属性,可以重新设置读、写、追加、非阻塞等标志*/
/*F_SETFL 将文件状态标志设置为第三个参数的值 (取为整型值)。*/
/* fcntl的F_SETOWN指令设置当前进程为设备文件owner*/
<
9b8a
br />
/* fcntl(fd, F_SETOWN, getpid());告诉驱动程序当前PID进程号
*/
fcntl(fd, F_SETOWN, getpid());
/*读取fd的文件状态标志位*/
Oflags = fcntl(fd, F_GETFL);
/*
设置fd的文件状态标志位为Oflags | FASYNC 即异步通知
调用fcntl(fd, F_SETFL, Oflags | FASYNC);函数时,会进入驱动程序的file_operations结构体执行fasync函数
*/
/*
每当FASYNC标志改变时,驱动程序中的fasync()函数将得以执行。
驱动中应该实现fasync()函数。
*/
fcntl(fd, F_SETFL, Oflags | FASYNC);
#endif
while (1)
{
/*判断返回值,非阻塞的话一读就会返回一个值,*/
ret = read(fd, &key_val, 1);
printf("key_val: 0x%x, ret = %d\n", key_val, ret);
}
return 0;
}
/*
fcnt1函数返回值说明
返回说明:
成功执行时,对于不同的操作,有不同的返回值
F_DUPFD: 新文件描述词
F_GETFD: 标志值
F_GETFL: 标志值
F_GETOWN: 文件描述词属主
F_GETSIG: 读写变得可行时将要发送的通告信号,或者0对于传统的SIGIO行为
*/
/*
getpid()用来取得目前进程的进程识别码,许多程序利用取到的
此值来建立临时文件,以避免临时文件相同带来的问题。*/
相关文章推荐
- 第二章、sql语句技巧和优化
- 机器学习之支持向量机: Support Vector Machines (SVM)
- android studio for android learning (三)我的第一个APP
- SSM+Maven实现无刷新三级联动
- gradient()函数的理解
- 设计模式总结篇系列:代理模式(Proxy)
- UVA 1583 - Digit Generator
- 判断字节序问题
- you belong with me(你属于我)
- Exploring Python Code Objects
- vba应用
- CCP浅谈
- MASM32使用教程
- 目标跟踪理论方法小结
- C++之各种二叉树的遍历
- 堆的相关知识
- Swagger使用总结
- 即时通讯:第一阶段(登录和注册)
- Struts2间接访问Servlet API(ActionContex--一般推荐使用)
- GDOI2016 Day1 T1 中学生数学题