免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1895 | 回复: 0
打印 上一主题 下一主题

字符设备驱动程序之定时器防抖动 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-02-09 09:39 |只看该作者 |倒序浏览
本帖最后由 ys9815076 于 2012-02-09 15:54 编辑

一、开发环境
•主  机:VMWare--Fedora 9
•Kernel:linux-2.6.32.2
•编译器:arm-linux-gcc-4.3.2

二、参考驱动程序
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/interrupt.h> /*linux中断*/
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <mach/gpio-fns.h>
#include <linux/sched.h>
struct cdev cdev;

#include <linux/poll.h>

static struct class *sixthdrv_class;

//volatile unsigned long *gpfcon;
//volatile unsigned long *gpfdat;

static struct timer_list buttons_timer;

static DECLARE_WAIT_QUEUE_HEAD(button_waitq);

/* 中断事件标志, 中断服务程序将它置1,sixth_drv_read将它清0 */
static volatile int ev_press = 0;

static struct fasync_struct *button_async;


struct pin_desc{
        unsigned int pin;
        unsigned int key_val;
};


/* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 0x05, 0x06 */
/* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 0x85, 0x86*/
static unsigned char key_val;

struct pin_desc pins_desc[6] = {
        {S3C2410_GPG(0), 0x01},
        {S3C2410_GPG(3), 0x02},
        {S3C2410_GPG(5), 0x03},
        {S3C2410_GPG(6), 0x04},
        {S3C2410_GPG(7), 0x05},
        {S3C2410_GPG(11),0x06},
};

static struct pin_desc *irq_pd;

//static atomic_t canopen = ATOMIC_INIT(1);     //定义原子变量并初始化为1

static DECLARE_MUTEX(button_lock);     //定义互斥锁


static irqreturn_t buttons_irq(int irq, void *dev_id)
{
        /* 发生中断20ms后启动定时器 */
        irq_pd = (struct pin_desc *)dev_id;
        mod_timer(&buttons_timer, jiffies+HZ/50);
        return IRQ_RETVAL(IRQ_HANDLED);
}

static int sixth_drv_open(struct inode *inode, struct file *file)
{
#if 0       
        if (!atomic_dec_and_test(&canopen))
        {
                atomic_inc(&canopen);
                return -EBUSY;
        }
#endif               

        if (file->f_flags & O_NONBLOCK)
        {
                if (down_trylock(&button_lock))
                        return -EBUSY;
        }
        else
        {
                /* 获取信号量 */
                down(&button_lock);
        }

        /* 设置GPG0,3,5,6,7,11为中断引脚 ,寄存器与中断引脚的联结*/
        s3c2410_gpio_cfgpin(S3C2410_GPG(0),S3C2410_GPG0_EINT;
        s3c2410_gpio_cfgpin(S3C2410_GPG(3),S3C2410_GPG3_EINT11);
        s3c2410_gpio_cfgpin(S3C2410_GPG(5),S3C2410_GPG5_EINT13);
        s3c2410_gpio_cfgpin(S3C2410_GPG(6),S3C2410_GPG6_EINT14);
        s3c2410_gpio_cfgpin(S3C2410_GPG(7),S3C2410_GPG7_EINT15);
        s3c2410_gpio_cfgpin(S3C2410_GPG(11),S3C2410_GPG11_EINT19);
        /*中断的注册*/
        request_irq(IRQ_EINT8,  buttons_irq, IRQF_DISABLED, "S1", &pins_desc[0]);
        request_irq(IRQ_EINT11, buttons_irq, IRQF_DISABLED, "S2", &pins_desc[1]);
        request_irq(IRQ_EINT13, buttons_irq, IRQF_DISABLED, "S3", &pins_desc[2]);
        request_irq(IRQ_EINT14, buttons_irq, IRQF_DISABLED, "S4", &pins_desc[3]);       
        request_irq(IRQ_EINT15, buttons_irq, IRQF_DISABLED, "S5", &pins_desc[4]);
        request_irq(IRQ_EINT19, buttons_irq, IRQF_DISABLED, "S6", &pins_desc[5]);
        /*中断类型的设置,为双边缘触发*/
        set_irq_type(IRQ_EINT8,IRQ_TYPE_EDGE_BOTH);
        set_irq_type(IRQ_EINT11,IRQ_TYPE_EDGE_BOTH);
        set_irq_type(IRQ_EINT13,IRQ_TYPE_EDGE_BOTH);
        set_irq_type(IRQ_EINT14,IRQ_TYPE_EDGE_BOTH);
        set_irq_type(IRQ_EINT15,IRQ_TYPE_EDGE_BOTH);
        set_irq_type(IRQ_EINT19,IRQ_TYPE_EDGE_BOTH);               

        return 0;
}

ssize_t sixth_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
        if (size != 1)
                return -EINVAL;

        if (file->f_flags & O_NONBLOCK)
        {
                if (!ev_press)
                        return -EAGAIN;
        }
        else
        {
                /* 如果没有按键动作, 休眠 */
                wait_event_interruptible(button_waitq, ev_press);
        }

        /* 如果有按键动作, 返回键值 */
        copy_to_user(buf, &key_val, 1);
        ev_press = 0;
       
        return 1;
}


int sixth_drv_close(struct inode *inode, struct file *file)
{
        //atomic_inc(&canopen);
        free_irq(IRQ_EINT8,  &pins_desc[0]);
        free_irq(IRQ_EINT11, &pins_desc[1]);
        free_irq(IRQ_EINT13, &pins_desc[2]);
        free_irq(IRQ_EINT14, &pins_desc[3]);
        free_irq(IRQ_EINT15, &pins_desc[4]);
        free_irq(IRQ_EINT19, &pins_desc[5]);
        up(&button_lock);
        return 0;
}

static unsigned sixth_drv_poll(struct file *file, poll_table *wait)
{
        unsigned int mask = 0;
        poll_wait(file, &button_waitq, wait); // 不会立即休眠

        if (ev_press)
                mask |= POLLIN | POLLRDNORM;

        return mask;
}

static int sixth_drv_fasync (int fd, struct file *filp, int on)
{
        printk("driver: sixth_drv_fasync\n";
        return fasync_helper (fd, filp, on, &button_async);
}


static struct file_operations sixth_drv_fops = {
        .owner   =  THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
        .open    =  sixth_drv_open,     
        .read         =  sixth_drv_read,          
        .release =  sixth_drv_close,
        .poll    =  sixth_drv_poll,
        .fasync         =  sixth_drv_fasync,
};

/*
  * 确定按键值
  */
static void buttons_timer_function(unsigned long data)
{
        struct pin_desc * pindesc = irq_pd;
        unsigned int pinval;

        if (!pindesc)
                return;
       
        pinval = s3c2410_gpio_getpin(pindesc->pin);

        if (pinval)
        {
                /* 松开 */
                key_val = 0x80 | pindesc->key_val;
        }
        else
        {
                /* 按下 */
                key_val = pindesc->key_val;
        }

    ev_press = 1;                  /* 表示中断发生了 */
    wake_up_interruptible(&button_waitq);   /* 唤醒休眠的进程 */
       
        kill_fasync (&button_async, SIGIO, POLL_IN);
}

int major;
static int sixth_drv_init(void)
{
        int result;
          dev_t devno = MKDEV(major, 0);

          /* 静态申请设备号*/
          if (major)
           result = register_chrdev_region(devno, 1, "sixth_drv_new";
          else  /* 动态分配设备号 */
          {
            result = alloc_chrdev_region(&devno, 0, 1, "sixth_drv_new";
            major = MAJOR(devno);
          }  
  
          if (result < 0)
            return result;

          /*初始化cdev结构*/
          cdev_init(&cdev, &sixth_drv_fops);
          cdev.owner = THIS_MODULE;
          cdev.ops = &sixth_drv_fops;
  
          /* 注册字符设备 */
          cdev_add(&cdev, MKDEV(major, 0), 1);

        sixthdrv_class = class_create(THIS_MODULE, "sixth_drv";
        device_create(sixthdrv_class, NULL, MKDEV(major,0), NULL, "buttons"; /* /dev/buttons */

        init_timer(&buttons_timer);
        buttons_timer.function = buttons_timer_function;
        //buttons_timer.expires  = 0;
        add_timer(&buttons_timer);
               
//        gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
//        gpfdat = gpfcon + 1;

        return 0;
}

static void sixth_drv_exit(void)
{
          cdev_del(&cdev);   /*注销设备*/
         
        unregister_chrdev_region(MKDEV(major, 0), 1); /*释放设备号*/
          device_destroy(sixthdrv_class,MKDEV(major,0));  //释放设备文件
          class_destroy(sixthdrv_class);//释放设备类
//        iounmap(gpfcon);
        //return 0;
}

module_init(sixth_drv_init);

module_exit(sixth_drv_exit);

MODULE_LICENSE("GPL";
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP