原创 【博客大赛】(原创)OK6410按键中断实现

2012-4-8 11:02 4520 22 22 分类: MCU/ 嵌入式

这里本人使用中断形式实现按键的驱动,首先还是先呈上源程序:

#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
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;
    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);

    /*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");

下面贴上测试程序^_^:

#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 press_cnt[6];

    fd = open("/dev/keyint",0);
    if(fd<0) {
      printf("open devie error\n");
      return -1;
    }

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

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

}

将测试程序编译后放到目标板上执行,可以看到哪个键按下时候会显示到终端。

本着互利互惠,共同分享的原则,依然奉献到底,贴上makefile:

执行程序makefile:

CROSS_COMPILE=/usr/local/arm/4.2.2-eabi/usr/bin/arm-unknown-linux-gnueabi-

keyint_test : keyint_test.c
    $(CROSS_COMPILE)gcc $^ -o $@

clean:
    rm -rf *~

模块编译makefile:

KDIR = /home/xu/Documents/linux-3.0.24
PWD  = $(shell pwd)

obj-m += keyint.o

default:
    $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules

clean:
    rm -rf *.o *~ *.mod.o *.mod.c

以上就是简单的按键驱动了,在记录自己的点滴的同时也希望能给比我更为初学的人(no offense/并无恶意笑脸)以帮助。

   

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
22
关闭 站长推荐上一条 /3 下一条