Linux按键信号 之 异步通知

一、异步通知概念:

  异步通知是指:一旦设备就绪,则主动通知应用程序,应用程序根本就不需要查询设备状态,类似于中断的概念,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。信号是异步的,一个进程不必通过任何操作来等待信号的到达。下面我们就看一下在linux中机制的实现方式。

  在Linux中,异步通知是使用信号来实现的,而在Linux,大概有30种信号,比如大家熟悉的ctrl+c的SIGINT信号,进程能够忽略或者捕获除过SIGSTOP和SIGKILL的全部信号,当信号背捕获以后,有相应的signal()函数来捕获信号,函数原型:sighandler_t signal(int signum, sighandler_t handler); 第 一个参数就是指定的信号的值,而第二个参数便是此信号的信号处理函数,当为SIG_IGN,表示信号被忽略,当为SIG_DFL时,表示采用系统的默认方 式来处理该信号。当然,信号处理函数也可以自己定义。当signal()调用成功后,返回处理函数handler值,调用失败后返回SIG_ERR。

二、信号处理要点:

①、注册信号处理函数:应用注册
②、发送者:驱动drv
③、接受者:应用app
④、发送方法:kill_fasync (&button_async, SIGIO, POLL_IN);

三、 原子操作:执行过程中不会被别的代码路径所中断的操作

常用原子操作函数:
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
int atomic_dec_and_test(atomic_t *v);  //自减操作后测试结果,0返回真,否则返回假 

四、信号量
1.定义:struct semaphore sem:
2.初始化:void sema_init(struct semaphore *sem, int val);
     void init_MUTEX(stuct semaphore *sem); //初始化为0
     static DECLARE_MUTEX(button_lock); //定义互斥锁

3.获得信号量: void down(struct semaphore *sem);
         int down_interruptible(struct semaphore *sem);
       int down_trylock(struct semaphore *sem);
4.释放信号量:

       void up(struct semaphore *sem);

五、阻塞:执行设备操作时若不能获得资源,则挂起进入休眠状态,被从调度器的运行队列移走,直到条件满足。

  非阻塞:执行设备操作时若不能获得资源,释放或查询等待条件满足。 : fd = open("/dev/buttons", O_RDWR | O_NONBLOCK);



六、示例代码:
1.驱动代码: signal_drv.c ========================================

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
#include <linux/poll.h>


static struct class *signaldrv_class;
static struct class_device *signaldrv_class_dev;

volatile unsigned long *gpfcon;
volatile unsigned long *gpfdat;

volatile unsigned long *gpgcon;
volatile unsigned long *gpgdat;


static DECLARE_WAIT_QUEUE_HEAD(button_waitq);

/* 中断事件标志, 中断服务程序将它置1,signal_drv_read将它清0 */
static volatile int ev_press = 0;

static struct fasync_struct *button_async;


struct pin_desc{
unsigned int pin;
unsigned int key_val;
};


/* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */
/* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */
static unsigned char key_val;

struct pin_desc pins_desc[4] = {
{S3C2410_GPF0, 0x01},
{S3C2410_GPF2, 0x02},
{S3C2410_GPG3, 0x03},
{S3C2410_GPG11, 0x04},
};

//static atomic_t canopen = ATOMIC_INIT(1); //定义原子变量并初始化为1

static DECLARE_MUTEX(button_lock); //定义互斥锁

/*
* 确定按键值
*/
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
struct pin_desc * pindesc = (struct pin_desc *)dev_id;
unsigned int pinval;

pinval = s3c2410_gpio_getpin(pindesc->pin);

if (pinval)
{
/* 松开 */
key_val = 0x80 | pindesc->key_val;
}
else
{
/* 按下 */
key_val = pindesc->key_val;
}

ev_press = 1; /* 表示中断发生了 */
wake_up_interruptible(&button_waitq); /* 唤醒休眠的进程 */

kill_fasync (&button_async, SIGIO, POLL_IN);

return IRQ_RETVAL(IRQ_HANDLED);
}

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/052e4d811623a2943cf5a15994d09e39.html