Chinaunix首页 | 论坛 | 博客

  • 博客访问: 481154
  • 博文数量: 86
  • 博客积分: 2010
  • 博客等级: 大尉
  • 技术积分: 878
  • 用 户 组: 普通用户
  • 注册时间: 2008-11-06 14:11
文章分类

全部博文(86)

文章存档

2010年(12)

2009年(60)

2008年(14)

我的朋友

分类: LINUX

2010-08-03 09:55:59



#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/hardware.h>

#define DEVICE_NAME "utukey"
#define KEY_TIME_DELAY (HZ/5)//200ms

#define KEY_TIME_DELAY1 (HZ/250)//4ms

#define KEYSTATUS_DOWNX 0 //刚被按下

#define KEYSTATUS_DOWN 1 //一直被按着hold

#define KEYSTATUS_UP 2 //按键抬起了


static void utu2440button_timer_callback(unsigned long data);//时间软中断定时器处理函数

static irqreturn_t utu2440_isr_kbd(int irq, void *dev_id, struct pt_regs *reg);//按键中断处理函数

static int utukey_open(struct inode *inode, struct file *filp);
static int utukey_release(struct inode *inode, struct file *filp);
void my_tasklet_func(unsigned long t);
int tasklet_time;
DECLARE_TASKLET(my_tasklet,my_tasklet_func,&tasklet_time);


static dev_t utukey_major=252;//主设备号自设定

unsigned int keynumber=6;//只是作为标记所用

struct utukey_dev_t
{
    struct cdev cdev;
    unsigned int keyStatus;
};
struct utukey_dev_t utukey_dev;
struct timer_list key_timer;

static const struct file_operations utukey_fops =
{
    .owner = THIS_MODULE,
    .open = utukey_open,
    .release = utukey_release,
};
/*打开函数*/
static int utukey_open(struct inode *inode, struct file *filp)
{
    filp->private_data = &utukey_dev;
    printk(KERN_NOTICE "utukey opened\n");
    return 0;
}
/*释放函数*/
static int utukey_release(struct inode *inode, struct file *filp)
{
    printk(KERN_NOTICE "utukey released\n");
    return 0;
}
/*中断服务程序*/
static irqreturn_t utu2440_isr_kbd(int irq, void *dev_id, struct pt_regs *reg)
{
   // int *key = (int*)dev_id;

   // printk(KERN_NOTICE "utukey interrupt key number is %d\n",*key);//传进了keynumber

    printk(KERN_NOTICE "utukey interrupt key number is %d\n",keynumber);
    if ( irq)
    {
      printk(KERN_NOTICE"bad irq %d in button\n", irq);
      return IRQ_NONE;
    }
    disable_irq(IRQ_EINT19);//先屏蔽此中断

    utukey_dev.keyStatus= KEYSTATUS_DOWNX; //表示刚被按下

    key_timer.expires = jiffies + KEY_TIME_DELAY1;//通过这个来实现去抖,并判断是否一直被按下,百分之一秒

    add_timer(&key_timer); //开始计时

   // tasklet_schedule(&my_tasklet);

    return IRQ_HANDLED;//表示处理好了 和 IRQ_NONE对应

}

/*timer 延时处理函数data参数来自于定时器结构中的data变量*/
static void utu2440button_timer_callback(unsigned long data)
{
    
    if (s3c2410_gpio_getpin(S3C2410_GPG11) == 0)
    {
        if (utukey_dev.keyStatus== KEYSTATUS_DOWNX)//从中断进入

        {
            printk(KERN_NOTICE "utukey is down\n");
            utukey_dev.keyStatus= KEYSTATUS_DOWN;//从中断进入的,证明按键已经被按下expires时间了,一直在被按着

            key_timer.expires = jiffies + KEY_TIME_DELAY; //判断是否还被按着,五分之一秒

            add_timer(&key_timer);
        }
     else //不是第一次进入定时器,表示按键一直被按着

        {
            printk(KERN_NOTICE "utukey is hold\n");
            key_timer.expires = jiffies + KEY_TIME_DELAY;//HOLD key,每隔200MS发送一次

            add_timer(&key_timer);
        }
    }
    else
    {
        utukey_dev.keyStatus= KEYSTATUS_UP;
        printk(KERN_NOTICE "utukey is up\n");
        enable_irq(IRQ_EINT19);//按键抬起的时候,重新开中断

    }
}
//中断下半部tasklet

void my_tasklet_func(unsigned long t)
{
  int data=*(int*)t;
  printk("tasklet is executing %d\n",data);
  (*(int*)t)++;
}


//insmod

static int __init utukey_init(void)
{
    int result,ret;
    dev_t devno = MKDEV(utukey_major,0);
    if (utukey_major)
    {
        result = register_chrdev_region(devno, 1, DEVICE_NAME);
    /*int register_chrdev_region(dev_t first, unsigned int count, char *name)
    First :要分配的设备编号范围的初始值(次设备号常设为0);
    Count:连续编号范围.(被使用只是一个要请求的范围,最终只能分配给你一个号码)
    Name:编号相关联的设备名称. (/proc/devices);
    */

    }
    else
    {
        result = alloc_chrdev_region(&devno, 0, 1, DEVICE_NAME);
    /*Int alloc_chrdev_region(dev_t *dev,unsigned int firstminor,unsigned int count,char *name);动态分配
    Firstminor : 通常为0;
    *dev:存放返回的设备号;
    */

        utukey_major = MAJOR(devno);
    }
    if (result < 0)
    {
        return result;
    }

    cdev_init(&utukey_dev.cdev,&utukey_fops);//字符设备初始化

    utukey_dev.cdev.owner = THIS_MODULE;
    utukey_dev.cdev.ops = &utukey_fops;
    utukey_dev.keyStatus = KEYSTATUS_UP;//按键初始状态为抬起

    ret = cdev_add(&utukey_dev.cdev, devno, 1);
    if (ret)
    {
        printk(KERN_NOTICE "Error %d adding utukey",ret);
    }
    
    s3c2410_gpio_cfgpin(S3C2410_GPG11, S3C2410_GPG11_EINT19);//申请中断

    set_irq_type(IRQ_EINT19, IRQT_FALLING);//设置为下降沿触发

    if (ret=request_irq(IRQ_EINT19, utu2440_isr_kbd, SA_INTERRUPT, DEVICE_NAME, NULL))//注册的中断号,中断服务程序,快速中断,设备名,传递的参数

    {
          
         printk(KERN_NOTICE"request irq in button failed key is %d,return is %d\n",keynumber,ret);
         return -1;
        }
    printk(KERN_NOTICE"request irq in button,successed\n");
     /*timer结构初始化*/
    key_timer.function = utu2440button_timer_callback;//timer的调用函数

    key_timer.data =keynumber;
    init_timer(&key_timer);
    return 0;
}
//rmmod

static void __exit utukey_exit(void)
{
    cdev_del(&utukey_dev.cdev);
    del_timer(&key_timer);
    free_irq(IRQ_EINT19,NULL);//释放irq中断void free_irq(unsigned int irq,void *dev_id); dev_id用于多个设备的中断共享

    unregister_chrdev_region(MKDEV(utukey_major,0),1);
/*
释放:
Void unregist_chrdev_region(dev_t first,unsigned int count);
*/

}

MODULE_AUTHOR("lwcheng");
MODULE_LICENSE("Dual BSD/GPL");

module_init(utukey_init);
module_exit(utukey_exit)


阅读(1786) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~