2440 Linux按鍵驅動及測試程式

來源:互聯網
上載者:User

原文地址:http://www.cnblogs.com/nick123/archive/2010/03/26/1696966.html

 以下是驅動程式:

/*本驅動程式運行於TQ2440開發板,核心版本2.6.31.6*/

#include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/poll.h> #include <linux/irq.h> #include <asm/irq.h> #include <linux/io.h>#include <linux/interrupt.h> #include <asm/uaccess.h> #include <mach/regs-clock.h>#include <plat/regs-adc.h> #include <mach/hardware.h> #include <linux/platform_device.h> #include <linux/cdev.h> #include <linux/miscdevice.h> #define DEVICE_NAME "tq2440-buttons"#define DEV_COUNT 1#define BUTTON_MAJOR 0#define BUTTON_MINOR 0#define MIN(A,B) (A)>(B)?(B):(A)/*等待隊列:*當沒有按鍵被按下時,如果有進程調用tq2440_buttons_read函數*它將休眠*/static DECLARE_WAIT_QUEUE_HEAD(button_waitq);/*中斷事件標誌,中斷服務程式將它置1,tq2440_buttons_read將它清0 */static volatile int ev_press = 0;/* 按鍵被按下的次數(準確地說,是發生中斷的次數) */static volatile int press_cnt[] = {0,0,0,0};static struct class *button_class; struct button_irqs_desc {int irq; //中斷號unsigned long flags; //中斷標誌,用來定義中斷的觸發方式 char *name; //中斷名稱};/*用來指定按鍵所用的外部中斷引腳及中斷觸發方式,名字*/static struct button_irqs_desc button_irqs[] = {{IRQ_EINT0,IRQ_TYPE_EDGE_FALLING,"KEY1"}, //K1{IRQ_EINT1,IRQ_TYPE_EDGE_FALLING,"KEY2"}, //K2{IRQ_EINT2,IRQ_TYPE_EDGE_FALLING,"KEY3"}, //K3{IRQ_EINT4,IRQ_TYPE_EDGE_FALLING,"KEY4"}, //K4};dev_t dev_num;static struct cdev * buttons_cdev_p; //cdev結構體指標/*卸載驅動程式*/static void __exit tq2440_buttons_exit(void){ cdev_del(buttons_cdev_p);//登出cdev kfree(buttons_cdev_p);//釋放裝置結構體記憶體 unregister_chrdev_region(dev_num,DEV_COUNT);//釋放裝置號}static irqreturn_t buttons_interrupt(int irq,void *dev_id){ volatile int *press_cnt = (volatile int *)dev_id; *press_cnt = *press_cnt + 1; /*按鍵計數器加1 */ ev_press = 1; /*表示中斷髮生了*/ wake_up_interruptible(&button_waitq); /*喚醒休眠的進程*/ printk(" IRQ:%d\n",irq); return IRQ_RETVAL(IRQ_HANDLED);}/*應用程式執行open("/dev/buttons",...)系統調用時,tq2440_buttons_open函數將 *被調用,它用來註冊4個按鍵的中斷處理常式*/static int tq2440_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;}/*應用程式對裝置檔案/dev/buttons執行close(...)時, *就會調用tq2440_buttons_close函數*/ static int tq2440_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;}/*應用程式對裝置檔案/dev/buttons執行read(...)時, *就會調用tq2440_buttons_read函數 */ static int tq2440_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肯定等於1,將它清0 */ ev_press = 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;}/*這個結構是字元驅動裝置程式的核心 *當應用程式操作裝置檔案時所調用的open,read,write等函數 *最終會調用這個結構中的對應函數 */static struct file_operations tq2440_buttons_fops = { .owner = THIS_MODULE,/*這是一個宏,指向編譯模組時自動建立的__this_module變數*/ .open = tq2440_buttons_open, .release = tq2440_buttons_close, .read = tq2440_buttons_read,};/* 初始化並註冊cdev*/static void buttons_cdev_setup(void){ int err; cdev_init(buttons_cdev_p,&tq2440_buttons_fops); buttons_cdev_p->owner = THIS_MODULE; buttons_cdev_p->ops = &tq2440_buttons_fops; err = cdev_add(buttons_cdev_p,dev_num,1); if(IS_ERR(&err)) printk(KERN_NOTICE "Error %d adding buttons",err);}static int __init tq2440_buttons_init(void){ int ret; /*註冊字元裝置驅動程式 *參數為主裝置號,裝置名稱字,file_operations結構體 *這樣,主裝置號就和具體的file_operations結構體聯絡起來了, *操作主裝置號為BUTTON_MAJOR的裝置檔案時,就會調用 *tq2440_buttons_fops中的相關成員函數,BUTTON_MAJOR可以設為0, *表示由核心自動分配主裝置號 */ if(BUTTON_MAJOR) //手動分配裝置號 { dev_num=MKDEV(BUTTON_MAJOR, BUTTON_MINOR); ret=register_chrdev_region(dev_num,DEV_COUNT,DEVICE_NAME); } else { //動態分配裝置號 ret = alloc_chrdev_region(&dev_num,BUTTON_MINOR,DEV_COUNT,DEVICE_NAME); } if(ret<0) { printk(DEVICE_NAME " can't register major number \n"); return ret; } /*動態申請cdev結構體的記憶體*/ buttons_cdev_p = kmalloc(sizeof(struct cdev),GFP_KERNEL); if(!buttons_cdev_p) //申請失敗 { ret = -ENOMEM; goto fial_malloc; } memset(buttons_cdev_p,0,sizeof(struct cdev)); buttons_cdev_setup(); //註冊一個類,使mdev可以在"/dev/"目錄下面 //建立裝置節點 button_class = class_create(THIS_MODULE,DEVICE_NAME); if(IS_ERR(button_class)) { printk("Error:Failed to creat button_class \n"); return -1; } //建立一個裝置節點,節點名為DEVICE_NAME device_create(button_class,NULL,dev_num,NULL,DEVICE_NAME); printk(DEVICE_NAME " initialized \n"); return 0; fial_malloc:unregister_chrdev_region(dev_num, 1);} /*這兩行制定驅動程式的初始化函數和卸載函數*/module_init(tq2440_buttons_init);module_exit(tq2440_buttons_exit)

下面是測試程式:

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/ioctl.h>int main(int argc,char **argv){    int i;    int ret;    int fd;    int press_cnt[4];    fd=open("/dev/tq2440-buttons",0);    if(fd<0)  {        printf("Can't open /dev/tq2440-buttons \n");        return -1;        }    //這是個無限迴圈,進程有可能在read函數中休眠,當有按鍵按下時,    //它才返回    while(1) {        ret = read(fd,press_cnt,sizeof(press_cnt));        if(ret<0)  {            printf("read err !\n");            continue;            }    //如果被按下的次數不為0,列印出來     for(i=0;i<sizeof(press_cnt)/sizeof(press_cnt[0]);i++)    {        if(press_cnt[i])                printf("Key%d has been pressed %d times \n",i+1,press_cnt[i]);        }           }//while            }

進入根檔案系統dev目錄,發現已經成功動分配裝置,並自動建立檔案節點

[nick@TQ2440 /dev]# ls -l tq*
crw-rw----    1 0        0        232,   0 Jan  1 00:00 tq2440-adc
crw-rw----    1 0        0        254,   0 Jan  1 00:00 tq2440-buttons
crw-rw----    1 0        0        231,   0 Jan  1 00:00 tq2440-leds
crw-rw----    1 0        0        204,  64 Jan  1 00:00 tq2440_serial0
crw-rw----    1 0        0        204,  65 Jan  1 00:00 tq2440_serial1
crw-rw----    1 0        0        204,  66 Jan  1 00:00 tq2440_serial2

下載核心後,運行測試程式

[nick@TQ2440 /app]# ./buttons_test &

查看中斷已經註冊成功

[nick@TQ2440 /proc]# cat interrupts
           CPU0
 16:          0    s3c-ext0  KEY1
 17:          0    s3c-ext0  KEY2
 18:          0    s3c-ext0  KEY3
 30:      27496         s3c  S3C2410 Timer Tick
 32:          0         s3c  s3c2410-lcd
 43:          0         s3c  s3c2440-i2c
 48:          0     s3c-ext  KEY4
 51:       2587     s3c-ext  eth0
 70:        156   s3c-uart0  s3c2440-uart
 71:       1839   s3c-uart0  s3c2440-uart
 83:          0           -  s3c2410-wdt
Err:          0

第一列表示中斷號

第二列表示這個中斷髮生的次數

第三列表示這個中斷的硬體訪問結構“struct irq_chip *chip"的名字,它在初始化中斷體繫結構時指定

第四列表示中斷的名稱

這時按下按鍵,輸出如下

 IRQ:48
Key4 has been pressed 1 times
 IRQ:16
Key1 has been pressed 1 times
 IRQ:18
Key3 has been pressed 1 times
 IRQ:48
Key4 has been pressed 1 times
 IRQ:16
Key1 has been pressed 1 times
 IRQ:17
Key2 has been pressed 1 times

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.