Home  >  Article  >  Database  >  kernel2.6.32.2 mini2440 led 驱动 之 中断(去抖动)处理

kernel2.6.32.2 mini2440 led 驱动 之 中断(去抖动)处理

WBOY
WBOYOriginal
2016-06-07 15:13:151102browse

#include linux/module.h #include linux/init.h #include linux/mm.h #include linux/slab.h #include linux/types.h #include linux/semaphore.h #include linux/cdev.h #include linux/fs.h #include linux/semaphore.h #include linux/irq.h #include asm

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#include
#include
#include

#define LED_MAJOR 250
#define LED_NAME "leds"

#define KEY_COUNT 4
#define KEY_DELAY HZ/50

DECLARE_WAIT_QUEUE_HEAD(r_wait);  //初始化等待队列
//wait_queue_head_t r_wait;
//init_waitqueue_head(&r_wait);
static struct timer_list key_timers[KEY_COUNT];  //定义定时器
static volatile bool idetify;

static void buttons_timer(unsigned long);

static unsigned long led_table [] = {
    S3C2410_GPB(5),
    S3C2410_GPB(6),
    S3C2410_GPB(7),
    S3C2410_GPB(8),
};//位地址

static unsigned int led_cfg_table [] = {
    S3C2410_GPIO_OUTPUT,
    S3C2410_GPIO_OUTPUT,
    S3C2410_GPIO_OUTPUT,
    S3C2410_GPIO_OUTPUT,
};//控制led为输入

struct button_irq_key{
    int irq;
    int pin;
    unsigned long flags;
    char *name;
};

static struct button_irq_key button_irqs[] = {
    {IRQ_EINT8, S3C2410_GPG(0), IRQF_TRIGGER_FALLING, "key1"},
    {IRQ_EINT11, S3C2410_GPG(3), IRQF_TRIGGER_FALLING, "key2"},
    {IRQ_EINT13, S3C2410_GPG(5), IRQF_TRIGGER_FALLING, "key3"},
    {IRQ_EINT14, S3C2410_GPG(6), IRQF_TRIGGER_FALLING, "key4"},
};

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


struct leds_cdev
{
    struct cdev cdev;
    struct semaphore sem;
};

int leds_major = LED_MAJOR;
struct leds_cdev dev;

static irqreturn_t buttons_interrupt(int irq, void *dev_id)//按键中断处理函数
{
//    volatile int *press_count = (volatile int*)dev_id;
    
    //disable_irq(irq);
    int key = 0;
    
    switch(irq){
    case 52:
    key = 0;
    break;
    case 55:
    key = 1;
    break;
    case 57:
    key = 2;
    break;
    case 58:
    key = 3;
    break;
    default:break;

    }
    
    key_timers[key].data = key;
    mod_timer(&key_timers[key], jiffies + KEY_DELAY);
    printk(KERN_EMERG "irq success");
    return IRQ_HANDLED;
}


static void buttons_timer(unsigned long arg)//定时器中断处理函数,去抖实现
{
    int key = arg;
    int condition;
    int nf;
    condition = s3c2410_gpio_getpin(button_irqs[key].pin);
    if(!condition)
    {
    while(!s3c2410_gpio_getpin(button_irqs[key].pin));

    key_timers[key].expires = jiffies + KEY_DELAY;
    add_timer(&key_timers[key]);
    idetify = 1;    
    
    printk(KERN_EMERG "lower is appear");
    }else{
    
    if(!idetify)
    return;

    press_cnt[key] += 1;
    nf = press_cnt[key]%2;
    s3c2410_gpio_setpin(led_table[key], nf);

    pressed = 1;
    wake_up_interruptible(&r_wait);
    idetify = 0;
    
    printk(KERN_EMERG "up is appear%d", nf);
//    enable_irq(button_irqs[key].irq);
    }

//    printk(KERN_EMERG "success of interruptible");
}

static int led_buttons_open(struct inode *inode, struct file *filp)
{
    int i;
    int err;
    for(i = 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;
/*    init_timer(&key_timers[i]);
    key_timers[i].data = i;
    key_timers[i].function = buttons_timer;
*/
    setup_timer(&key_timers[i], buttons_timer, i);初始化定时器
    }
    //key_timers[0].expires = jiffies + 3 * HZ;
    //add_timer(&key_timers[0]);
    if(err){
    i--;
    for(; i >= 0; i--)
    free_irq(button_irqs[i].irq, (void *)press_cnt[i]);
    return -EBUSY;
    }
    
    return 0;
}

static ssize_t led_buttons_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
{
    unsigned long err;
    wait_event_interruptible(r_wait, pressed);
    
    pressed = 0;
    
    err = copy_to_user(buf, (const void *)press_cnt, sizeof(press_cnt));
    memset((void *)press_cnt, 0, sizeof(press_cnt));
    return err ? -EFAULT : 0 ;
}

static int led_buttons_close(struct inode *inode, struct file *filp)
{
    int i;
    for(i = 0; i     free_irq(button_irqs[i].irq, (void*)&press_cnt[i]);//释放中断号
    del_timer(&key_timers[i]);
    }
    return 0;
}

static int leds_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
    switch(cmd)
    {
        case 0:
        if(arg > 4){
            return -EINVAL;
            }
        down(&dev.sem);
        s3c2410_gpio_setpin(led_table[arg], 0);
        up(&dev.sem);
        return 0;
        case 1:
        if(arg > 4){
        return -EINVAL;
        }
        down(&dev.sem);
        s3c2410_gpio_setpin(led_table[arg], 1);
        up(&dev.sem);
        return 0;
        default:
            return -EINVAL;
    }
}

struct file_operations cdev_fops = {
    .owner = THIS_MODULE,
    .ioctl = leds_ioctl,
    .open = led_buttons_open,
    .read = led_buttons_read,
    .release = led_buttons_close,
};

static void leds_setup(struct leds_cdev *dev, int index)
{
    int err, devno = MKDEV(leds_major, index);
    cdev_init(&dev->cdev, &cdev_fops);
    dev->cdev.owner = THIS_MODULE;
    dev->cdev.ops = &cdev_fops;
    err = cdev_add(&dev->cdev, devno, 1);
    if(err)
        printk(KERN_NOTICE "Error %d adding LED %d\n", err, index);
}

static int __init dev_init(void)       //module初始化与注册

{

    int result;
    int i;
//    struct class *my_class;
    dev_t devno = MKDEV(leds_major, 0);
    for(i = 0; i     s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);
    s3c2410_gpio_setpin(led_table[i], 0);
    }
    
    if(leds_major)
    result = register_chrdev_region(devno, 1, "leds");
    else{
    result = alloc_chrdev_region(&devno, 0, 1, "leds");
    leds_major = devno;
    }
    
    if(result     return result;
    leds_setup(&dev, 0);
    sema_init(&dev.sem, 1);
/*    my_class = class_create(THIS_MODULE, LED_NAME);
    if(IS_ERR(my_class))
    {
    printk("Err:failed in creating class.\n");
    return -1;
    }
    device_create(my_class, NULL, MKDEV(leds_major, 0), LED_NAME, 0);
*/
    return 0;

}

void __exit dev_exit(void)
{
    cdev_del(&dev.cdev);
    unregister_chrdev_region(MKDEV(leds_major, 0), 1);
}

module_init(dev_init);
module_exit(dev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("emperor");

MODULE_DESCRIPTION("LED MODULE");

自行分析

亲测通过

如果BUG,望大伙提出来,互相改善学习一下。

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn