LINUX 按鍵中斷

這裏主要是仿照《嵌入式Linux開發完全手冊》 上的例子寫的,下載見http://www.linuxidc.com/Linux/2011-01/31114.htm ,只是增加了別外兩個按按鍵。在我的mini2440開發板上有6個按鍵。在上兩篇文章中,主要分析了驅動中的整體的流程,現在來看一個具體的例子,是如何使用中斷的。
1. 模塊的初始化函數和卸載函數

/* 執行"insmod mini2440_buttons.ko"命令時就會調用這個函數*/
static int __init mini2440_buttons_init (void)
{
  int ret;
/*這裏主要是註冊設備驅動程序,參數爲主設備號,如果BUTTON_MAJOR設爲0,表示由內核自動分配主設備號,設備的名字,file_operations結構,操作主調和號爲BUTTON_MAJOR的設備文件時,就會調用mini2440_buttons_fops中的相關成員函數*/
  ret = register_chrdev(BUTTON_MAJOR,DEVICE_NAME,&mini2440_buttons_fops);
  if(ret < 0)
  {
    printk(DEVICE_NAME "can't register major number\n");
    return ret ;
  }
  printk(DEVICE_NAME"initialized\n");
  return 0;
}
/* 執行 rmmod mini2440_buttons.ko0 命令時就會調用這個函數 */
static void __exit mini2440_buttons_exit(void)
{
//卸載驅動程序

  unregister_chrdev(BUTTON_MAJOR,DEVICE_NAME);
}
//指定驅動程序的初始化函數和卸載函數

module_init(mini2440_buttons_init);
module_exit(mini2440_buttons_exit);

   下面這個結構體是每一個字符驅動程序都是要用到的。這裏定義了應用程序可以使用的設備操作函數,只有在這個結構體中的函數,在應用程序中才可以使用,在下面的驅動程序中要實現下面的函數。

/* 這個結構是字符設備驅動程序的核心,當應用程序操作設備文件時所調用的open,read,write等函數,最終會調用這個結構中的對應函數*/
static struct file_operations mini2440_buttons_fops =
  {
    .owner = THIS_MODULE, 
//這是 個宏,指向編譯模塊時自動創建的_this_module變量

    .open = mini2440_buttons_open,
    .release = mini2440_buttons_close,
    .read = mini2440_buttons_read,
  };

2. mini2440_buttons_open函數
   在應用程序執行“open("/dev/buttons",..)"系統調用時,mini2440_buttons_open函數將被調用。這用來註冊6個按鍵的中斷處理程序

static int mini2440_buttons_open(struct inode *inode,struct file *file)
{
  int i;
  int err;
  for (i=0;i<sizeof(button_irqs)/sizeof(button_irqs[0]);i++)
  { //註冊中斷處理函數 一共六個
    err = request_irq(button_irqs[i].irq,buttons_interrupt,button_irqs[i].flags,button_irqs[i].name,(void *)&press_cnt[i]);
    if (err)
      break;
  }
  if(err) //出錯處理函數,如果出錯釋放已經註冊的中斷
  {
    i--; 
    for(;i>=0;i--)
      free_irq(button_irqs[i].irq,(void *)&press_cnt[i]);
    return -EBUSY;
  }
  return 0;
}

requst_irq函數執行成功後,這6個按鍵所用的GPIO引腳的功能被設爲外部中斷,觸發方式爲下降沿觸發,中斷處理函數爲buttons_interrupt.最後一個參數“(void *)&press_cnt[i]”將在buttons_interrupt函數中用到,它用來 存儲按鍵被按下的次數。參數button_irqs的定義如下:

struct button_irq_desc
{
  int irq;//中斷號
  unsigned long flags; //中斷標誌,用來定義中斷的觸發方式
  char *name; //中斷名稱
};

static struct button_irq_desc button_irqs[] =
  {  //下面是按鍵對應的外部的中斷號,觸發方式,名稱
    {IRQ_EINT8,IRQF_TRIGGER_FALLING,"KEY0"},
    {IRQ_EINT11,IRQF_TRIGGER_FALLING,"KEY1"},
    {IRQ_EINT13,IRQF_TRIGGER_FALLING,"KEY2"},
    {IRQ_EINT14,IRQF_TRIGGER_FALLING,"KEY3"},
    {IRQ_EINT15,IRQF_TRIGGER_FALLING,"KEY4"}, 
    {IRQ_EINT19,IRQF_TRIGGER_FALLING,"KEY5"},
  };

3. mini2440_buttons_close函數
mini2440_buttons_close函數的作用是用來卸載6個按鍵的中斷處理函數代碼如下:

/* 應用程序對設備文件/dev/buttons執行close(...)時。就會調用mini2440_buttons_close函數*/
static int mini2440_buttons_close(struct inode *inode,struct file *file)
{
  int i;
  for(i=0;i<sizeof(button_irqs)/sizeof(button_irqs[0]);i++)
  { 
//釋放已註冊的函數

    free_irq(button_irqs[i].irq,(void *)&press_cnt[i]);
  }
  return 0;
}

4. mini2440_buttons_read函數
中斷處理函數會在press_cnt數組中記錄按鍵被按下的次數。mini_buttons_read函數,首先判斷是否按鍵再次按下,如果沒有則休眠;否則讀取press_cnt數組的數據,

/*等待隊列:
 當沒有按鍵被按下時,如果有進程調用mini2440_buttons_read函數,它將休眠*/

static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
/*中斷事件標誌,中斷服務程序將它置1,mini2440_buttons_read將它清0*/
static volatile int ev_press = 0;
/*應用程序對設備文件/dev/buttons執行read(...)時,就會調用mini2440_buttons_read函數*/
static int mini2440_buttons_read(struct file *filp,char __user *buff,size_t count,loff_t *offp)
{
  unsigned long err;
 //如果ev_press等於0,休眠
  wait_event_interruptible(button_waitq,ev_press);
  ev_press = 0;// 執行到這裏是ev_press肯定是1,將它清0
  //將按鍵狀態複製給用戶,並清0
  err = copy_to_user(buff,(const void *)press_cnt,min(sizeof(press_cnt),count));
  memset((void *)press_cnt,0,sizeof(press_cnt));

  return err ? -EFAULT:0;
}

   
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章