4.查詢方式來寫按鍵驅動程序(詳解)


本節目標:

   寫second程序,內容:通過查詢方式驅動按鍵

1.寫出框架

1.1寫file_oprations結構體,second_drv_open函數,second_drv_read函數

1.2寫入口函數,並自動創建設備節點,修飾入口函數

1.3寫出口函數,並自動注銷設備節點,修飾出口函數

1.4 寫MODULE_LICENSE(“GPL v2”)聲明函數許可證

1.5 在入口函數中,利用class_create和class_device_create自動創建設備節點

在出口函數中,利用class_destroy和class_device_unregister注銷設備節點

2.寫Makefile並編譯后,放在板子上insmod后,看看lsmod、cat /porc/devices、 ls -l /dev/second是否加載成功,如下圖:

3.在框架中實現硬件操作

3.1看原理圖,確定用什么寄存器控制按鍵引腳,如下圖

 

按鍵0~3分別是GPF0,GPF2,GPG3,GPG11

由於是使用查詢模式,並不是外部中斷模式

所以配置 GPFCON(0x56000050)的位[0:1]、位[4:5]等於0x00(輸入模式)

GPGCON(0x56000060)的位[6:7]、位[22:23]等於0x00

通過GPGDAT (0x56000054) 和GPGDAT(0x56000064)來查詢按鍵狀態

3.2寫代碼

init入口函數中使用ioremap()函數映射寄存器虛擬地址

exit出口函數中使用iounmap()函數注銷虛擬地址

open函數中配置GPxCON初始化按鍵

read函數中先檢查讀出的字符是否是4個,然后獲取GPxDAT狀態,用key_vals[4]數組保存4個按鍵值,最后使用 copy_to_user(buf, key_vals,sizeof(key_vals)) 上傳給用戶層

4.寫測試程序Secondtext.c

用法就是./ Secondtext

使用read(fd,val,sizeof(val));函數讀取內核層的數據

5.然后輸入./ Secondtext進行測試,按下key2時,如下圖:

 

 

6.使用./ Secondtext & 后台運行測試程序

后台會一直運行這個程序,當我們有按鍵按下時,就會打印數據出來,如下圖:

 

 

7.通過top命令可以發現這個./ Secondtext占了CPU的99%時間

 

因為,我們的Secondtext測試程序一直在while中通過查詢方式讀取按鍵狀態,這樣的效率是非常低的.

接下來開始使用中斷方式來改進按鍵驅動程序,提高效率,先來分析內核里中斷如何運行的。 

 

 

本節Secondtext測試程序代碼如下:

#include <sys/types.h>    //調用sys目錄下types.h文件
#include <sys/stat.h>      //stat.h獲取文件屬性
#include <fcntl.h>
#include <stdio.h>
#include <string.h>


/*secondtext while一直獲取按鍵信息 */ int main(int argc,char **argv) { int fd,ret; unsigned char val[4]; fd=open("/dev/buttons",O_RDWR); if(fd<0) {printf("can't open!!!\n"); return -1;} while(1) { ret=read(fd,val,sizeof(val)); if(ret<0) { printf("read err!\n"); continue; } if((val[0]&val[1]&val[2]&val[3])==0) printf("key0=%d,key1=%d,key2=%d,key3=%d\n",val[0],val[1],val[2],val[3]); } return 0; }

 

本節second.c按鍵驅動代碼如下:

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



static struct class *seconddrv_class;               //創建一個class類
static struct class_device   *seconddrv_class_devs; //創建類的設備

volatile unsigned long *GPFcon;       
volatile unsigned long *GPFdat;
volatile unsigned long *GPGcon;       
volatile unsigned long *GPGdat;

static int second_drv_open(struct inode *inode, struct file  *file)
{
    /*初始化按鍵*/   
   /* 配置 GPFCON(0x56000050)的位[0:1]、位[4:5]等於0x00(輸入模式)
      GPGCON(0x56000060)的位[6:7]、位[22:23]等於0x00*/
    *GPFcon&=~((0x3<<0)|(0x3<<4));
    *GPGcon&=~((0x3<<6)|(0x3<<22));

   return 0;
}

static int second_drv_read(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
         unsigned char key_vals[4];

       /*按鍵0~3分別是GPF0,GPF2,GPG3,GPG11*/
        if(count!=sizeof(key_vals))
                 return EINVAL;       

          key_vals[0]=(*GPFdat>>0)&0X01;   
          key_vals[1]=(*GPFdat>>2)&0X01;           
          key_vals[2]=(*GPGdat>>3)&0X01; 
          key_vals[3]=(*GPGdat>>11)&0X01;   

     /*上傳給用戶層*/
       if(copy_to_user(buf,key_vals,sizeof(key_vals)))
        return EFAULT;
  return 0;

}

 

static struct file_operations second_drv_fops={
       .owner = THIS_MODULE,
       .open = second_drv_open,
       .read = second_drv_read,};
volatile int second_major; //保存主設備號 static int second_drv_init(void) { second_major=register_chrdev(0,"second_drv",&second_drv_fops); //創建驅動 seconddrv_class=class_create(THIS_MODULE,"second_dev"); //創建類名 seconddrv_class_devs=class_device_create(seconddrv_class, NULL, MKDEV(second_major,0), NULL,"buttons");
/*申請虛擬地址,然后配置寄存器*/ /* GPFCON(0x56000050) GPGCON(0x56000060) */ GPFcon=ioremap(0x56000050,16); GPFdat=GPFcon+1; GPGcon=ioremap(0x56000060,16); GPGdat=GPGcon+1; return 0; } static int second_drv_exit(void) { unregister_chrdev(second_major,"second_drv"); //卸載驅動 class_device_unregister(seconddrv_class_devs); //卸載類設備 class_destroy(seconddrv_class); //卸載類 /*注銷虛擬地址*/ iounmap(GPFcon); iounmap(GPGcon);
return 0; } module_init(second_drv_init); module_exit(second_drv_exit); MODULE_LICENSE("GPL v2");

 

接下來,下章學習內核中的中斷如何實現的,來使用中斷按鍵:

5.分析內核中斷運行過程,以及中斷3大結構體:irq_desc、irq_chip、irqaction(詳解)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM