飛凌 ok6410 按鍵驅動源碼及測試代碼

因爲OK6410的GPIO按鍵中斷已經被飛凌自帶的按鍵驅動註冊,因此運行咱們編寫的按鍵驅動前要先去掉飛凌自帶的按鍵驅動,方法:make menuconfig->Device Drivers->input device support->Key Boards->GPIO Buttons 去掉前面的*,即不選該項便可。node

key.clinux

#include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/gpio.h>
 #include <linux/types.h>
 #include <linux/cdev.h>
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/device.h>
 #include <linux/poll.h>
 #include <linux/semaphore.h>
 #include <linux/timer.h>

 #include <asm/irq.h>
 #include <asm/uaccess.h>

 //#include <mach/hardware.h>
 #include <mach/irqs.h>


 #define DEVICE_NAME "keyint"
 #define KEYNUM 6
 dev_t devid;

 //static DEFINE_SEMAPHORE(key_lock);  //declare a mutex lock for keyint
   //定義一個信號量
 struct semaphore key_lock;
 static struct fasync_struct *key_async;
 static struct timer_list key_timer;

 struct key_irq_desc {
     int irq;        //irq num
     unsigned long flags;    //irq flags,identified the way of irq here,eq.edge,level
     char *name;        //irq name
 };

 static struct key_irq_desc key_irqs[] = {
	 //降低沿產生中斷
     {IRQ_EINT(0), IRQF_TRIGGER_FALLING, "KEY1"},
     {IRQ_EINT(1), IRQF_TRIGGER_FALLING, "KEY2"},
     {IRQ_EINT(2), IRQF_TRIGGER_FALLING, "KEY3"},
     {IRQ_EINT(3), IRQF_TRIGGER_FALLING, "KEY4"},
     {IRQ_EINT(4), IRQF_TRIGGER_FALLING, "KEY5"},
     {IRQ_EINT(5), IRQF_TRIGGER_FALLING, "KEY6"},
 };

 /*define a waiting queue here*/
 static DECLARE_WAIT_QUEUE_HEAD(key_waitq);

 /*define a event flag ev_press*/
 static volatile int ev_press = 0;

 static volatile int press_cnt[KEYNUM] = {0,0,0,0,0,0};




 /*中斷處理函數*/
 static irqreturn_t keys_interrupt(int irq, void *dev_id)
 {
     volatile int *press_cnt = (volatile int *) dev_id;
        /*set the pressed key flag(must do here due to not be static value)*/
     *press_cnt = *press_cnt + 1;

	 //延時10ms後執行定時器處理函數
     mod_timer(&key_timer,jiffies+HZ/100);        //start timer after 10ms

     return IRQ_RETVAL(IRQ_HANDLED);
 }


//定時器處理函數
 static void key_timer_func(unsigned long data)
 {
         
     ev_press = 1;
	 //喚醒等待隊列
     wake_up_interruptible(&key_waitq);
     kill_fasync(&key_async, SIGIO, POLL_IN);
 }


 static int key_fasync(int fd, struct file *filp, int on)
 {
     printk("Function key_fasync\n");
     return fasync_helper(fd,filp,on,&key_async);
 }



 static unsigned key_poll(struct file *file, poll_table *wait)
 {
     unsigned int mask=0;
	 //指明要使用的等待隊列
     poll_wait(file,&key_waitq,wait);


	//返回掩碼
     if(ev_press)
     mask |= POLL_IN | POLLRDNORM;

     printk("poll wait\n");

     return mask;
 }

 static int key_open(struct inode *inode, struct file *file)
 {
     int num;

     if(file->f_flags & O_NONBLOCK) {
       if(down_trylock(&key_lock)) return -EBUSY;
     }

     else {
       down(&key_lock);
     }
     
	 //爲每一個按鍵註冊中斷處理程序
     for(num=0;num<KEYNUM;num++) {
       request_irq(key_irqs[num].irq, keys_interrupt, key_irqs[num].flags, key_irqs[num].name, (void *)&press_cnt[num]);
     }


     return 0;
 }

 static int key_close(struct inode *inode, struct file *file)
 {
     int num;
	 //釋放中斷號
     for(num=0;num<6;num++) {
       free_irq(key_irqs[num].irq, (void *)&press_cnt[num]);
     }
     up(&key_lock);

     printk("key_close free irqs\n");

     return 0;
 }

 static int key_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
 {
 //    unsigned int err;
     
	 //判斷是阻塞讀仍是非阻塞讀
     if(filp->f_flags & O_NONBLOCK) {
       if(!ev_press)  return -EAGAIN;
     }

     else {
       /*if ev_press==0,then sleep*/
	   /*阻塞,當有按鍵按下時(中斷)被喚醒*/
       wait_event_interruptible(key_waitq,ev_press);
     }
	 //阻塞結束,有鍵按下了

     ev_press = 0;

	 //拷貝數據到用戶空間
     copy_to_user(buff,(const void *)press_cnt,min(sizeof(press_cnt),count));
     memset((void *)press_cnt,0,sizeof(press_cnt));

 //    printk("read and clean press_cnt\n");

     return 1;
 }

 static struct file_operations key_ops = {
     .owner     = THIS_MODULE,
     .open     = key_open,
     .release = key_close,
     .read     = key_read,
     .poll     = key_poll,
     .fasync     = key_fasync,
 };

 static struct cdev *cdev_keyint;
 static struct class *keyint_class;



 //模塊初始化函數
 static int __init s3c6410_keyint_init(void) {
     int val;
     
     /*timer initial */
     init_timer(&key_timer);
     key_timer.function = key_timer_func;
     add_timer(&key_timer);

	     /*初始化信號量*/
	    init_MUTEX(&key_lock);
     /*register device*/
     val = alloc_chrdev_region(&devid,0,1,DEVICE_NAME);
     if(val) {
       return -1;
       printk("register keyint error\n");
     }

     cdev_keyint = cdev_alloc();
     cdev_init(cdev_keyint, &key_ops);
     cdev_keyint->owner = THIS_MODULE;
     cdev_keyint->ops   = &key_ops;
     
     val = cdev_add(cdev_keyint,devid,1);
     if(val) {
       return -1;
       printk("add device error\n");
     }

     keyint_class = class_create(THIS_MODULE,DEVICE_NAME);
     device_create(keyint_class,NULL,devid,NULL,"%s",DEVICE_NAME);
     
     printk("KEY initialezed ^_^\n");
     return 0;
 }

 static void __exit s3c6410_keyint_exit(void)
 {
      cdev_del(cdev_keyint);
     device_destroy(keyint_class,devid);
     class_destroy(keyint_class);
     unregister_chrdev_region(devid,1);
 }


 module_init(s3c6410_keyint_init);
 module_exit(s3c6410_keyint_exit);

 MODULE_LICENSE("GPL");

Makefileasync

ifneq ($(KERNELRELEASE),)
	obj-m := key.o
else
 
KDIR := /forlinux/linux-3.0.1
all:
	make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
clean:
	rm -f *.ko *.o *.mod.o *.mod.c *.symvers
endif

產生.ko文件進行安裝模塊和設備 insmod,這裏不須要mknod由於函數裏調用了class_create和device_create會自動建立設備節點。ide

測試代碼函數

#include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/ioctl.h>

 int main(int argc, char **argv)
 {
     int fd;
     int val;
     int i;
     int key_value[6];
	      
     fd = open("/dev/keybutton",0);
     if(fd<0) {
       printf("open devie error\n");
       return -1;
     }

     while(1) {
       val = read(fd,key_value, sizeof(key_value));
       if(val<0) {
         printf("read error\n");
         continue;
       }

       for(i=0;i<6;i++) {
          if(key_value[i])
          printf("KEY%d pressed\n",(i+1),key_value[i]);
         
       }  
       
     }
     close(fd);
     return 0;

 }
相關文章
相關標籤/搜索