arm驅動程序——按鍵程序6_互斥—信號量(韋東山的視頻總結及針對linux-2.6.30)

相關源碼在資源中下載。

信號量實現互斥的一個方法。

只有得到信號量的進程才能執行臨界區的代碼,當得不到信號量時,進程會進入休眠等待狀態。

用到的函數,結構體及其他:

/*定義並初始化信號量*/

DECLARE_MUTEX(name)

/*獲得信號量,此時進程處於D狀態,

 *進程處於睡眠狀態,但是此刻進程是不可中斷的。

 *不可中斷,指的並不是CPU不響應外部硬件的中斷,而是指進程不響應異步信號。

 */

void down(struct semaphore *sem)

/*釋放信號量*/

void up(struct semaphore *sem)

驅動程序:

#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 <linux/device.h>
#include <linux/poll.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <mach/irqs.h>
#include <mach/regs-gpio.h>
/*不同的linux版本,頭文件會有所不同*/


static int major;
/*定義一個類*/
static struct class *second_key_class;
/*定義一個設備*/
static struct device *second_key_device;
/*定義一個等待的頭文件*/
static DECLARE_WAIT_QUEUE_HEAD(button_wait_head);
/*定義一個定時器*/
struct timer_list second_key_timer;
/*中斷事件標誌*/
static int ev_press=0;
static unsigned int key_val;
static struct fasync_struct *fasync_q;
/*定義信號量並初始化*/
static DECLARE_MUTEX(button_sem);
/*定義一個引腳描述的結構體*/
struct pindec 
{
   unsigned int pin;
   unsigned int val;
};
/*定義引腳描述的數組,
 *鬆開按鍵時,值爲;0x01,0x02,0x03,0x04
 *按下按鍵時,值爲; 0x81,0x82,0x83,0x84*/
static struct pindec pin_dec[4]={
   {S3C2410_GPF1,0x01},
   {S3C2410_GPF4,0x02},
   {S3C2410_GPF2,0x03},
   {S3C2410_GPF0,0x04},
};
static struct pindec *irq_dec;
static irqreturn_t button_irq(int irq,void *dev)
{
   irq_dec = (struct pindec*)dev;
    /*修改定時器的超時時間*/
   mod_timer(&second_key_timer,jiffies+HZ/100);
   return IRQ_RETVAL(IRQ_HANDLED);
}
static int second_key_fasync_open(struct inode *inode, struct file *file)
{
   /*獲取信號量*/
   down(&button_sem);
   /*註冊中斷*/
   request_irq(IRQ_EINT1,button_irq,IRQ_TYPE_EDGE_BOTH,"s1",&pin_dec[0]);
   request_irq(IRQ_EINT4,button_irq,IRQ_TYPE_EDGE_BOTH,"s2",&pin_dec[1]);
   request_irq(IRQ_EINT2,button_irq,IRQ_TYPE_EDGE_BOTH,"s3",&pin_dec[2]);
   request_irq(IRQ_EINT0,button_irq,IRQ_TYPE_EDGE_BOTH,"s4",&pin_dec[3]);
   return 0;
}


static ssize_t second_key_fasync_read(struct file *file, char __user *user_buffer, 
                                    size_t count, loff_t *ppos)
{
   if(count != 1)
       return -EINVAL;
    /*ev_press中斷標誌爲0,休眠,即未發生中斷時,休眠*/
   wait_event_interruptible(button_wait_head,ev_press);
    /*傳數據到用戶空間*/
   copy_to_user(user_buffer,&key_val,1);
    /*中斷結束,中斷標誌置0,休眠*/
   ev_press = 0;
   return 1;
}
static unsigned int second_key_poll(struct file *file, 
                                    struct poll_table_struct*wait)
{
     unsigned int mask = 0;
     /*掛載到隊列中去*/
     poll_wait(file, &button_wait_head, wait);
     if(ev_press)
          mask = POLLIN; /*普通或優先級帶數據可讀*/
     return mask;
}
static int second_key_fasync(int fd, struct file * file, int on)
{
     int result;
     result = fasync_helper(fd, file, on, &fasync_q);
     return (result);
}


static int second_key_fasync_close(struct inode *inode, struct file *file)
{
     free_irq(IRQ_EINT1,&pin_dec[0]);
     free_irq(IRQ_EINT4,&pin_dec[1]);
     free_irq(IRQ_EINT2,&pin_dec[2]);
     free_irq(IRQ_EINT0,&pin_dec[3]);
      /*釋放信號量*/
     up(&button_sem);
     return 0;
}
void second_timer_function(unsigned long data)
{
     unsigned int pinval;
     struct pindec *pin_desc =irq_dec;
      /*獲得引腳狀態*/
     pinval=s3c2410_gpio_getpin(pin_desc->pin);
     if(pinval)
         key_val = pin_desc->val;
     else
         key_val = pin_desc->val|0x80;
      /*喚醒*/
     ev_press = 1;
     wake_up_interruptible(&button_wait_head);
     kill_fasync(&fasync_q, SIGIO, POLL_IN);
}
/*定義一個file_operations結構*/
static struct file_operations second_key_fasync_fops = {
     .owner = THIS_MODULE,
     .open  = second_key_fasync_open,
     .read  = second_key_fasync_read,
     .poll  = second_key_poll,
     .release = second_key_fasync_close,
     .fasync= second_key_fasync,
};
static int second_key_init(void)
{
     /*註冊*/
     major = register_chrdev(0,"second_key",&second_key_fasync_fops);
     /*創建類在/sys/class可以查找到*/
     second_key_class = class_create(THIS_MODULE,"second_key_class");
     /*類下創建設備可以在/sys/class/second_key_class可以查找到*/
     second_key_device = 
         device_create(second_key_class,NULL,MKDEV(major,0),NULL,"second_key_device");
     /*初始化定時器*/
     init_timer(&second_key_timer);
     second_key_timer.function = second_timer_function;
     /*啓動定時器*/
     add_timer(&second_key_timer);
     return 0;
 }
static void second_key_exit(void)
{
    /*註銷*/
    unregister_chrdev(major,"second_key");
    /*刪除定時器*/
    del_timer(&second_key_timer);
    /*註銷類*/
    device_unregister(second_key_device);
    /*銷燬定義的類*/
    class_destroy(second_key_class);
}
/*修飾*/
module_init(second_key_init);
module_exit(second_key_exit);
MODULE_LICENSE("GPL");

測試程序:

#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
#include<signal.h>
int fd;
/*接到信號調用的函數*/
void my_signal_fun(int signum)
{
    static char key_val;
    read(fd,&key_val,1);
    printf("key_val: 0x%x\n",key_val);
}
int main(int argc,char **argv){
    int oflags;
    fd=open("/dev/second_key_device",O_RDWR);
    if(fd<0)
        printf("can't open!\n");
    /*void (*signal)(int signo,void(*func)(int))(int )
     *signo : 信號名,func;信號處理程序
     */
      signal(SIGIO,my_signal_fun);
     /*F_SETOWN設置接收SIGIO和SIGURG信號的進程ID*/
      fcntl(fd,F_SETOWN,getpid()); 
     /*F_GETFL 獲得文件狀態標誌 */
      oflags = fcntl(fd,F_GETFL); 
     /*F_SETFL設置文件狀態標誌*/
      fcntl(fd,F_SETFL,oflags | FASYNC);
      while(1){
          sleep(1000);
      }
     return 0;
}

發佈了36 篇原創文章 · 獲贊 7 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章