×
单片机 > 单片机程序设计 > 详情

字符设备驱动-高级篇按键中断程序驱动

发布时间:2020-08-28 发布时间:
|
驱动源码:
 
#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 "asm/arch/regs-gpio.h"
#include "asm/hardware.h"
 
int major = 0;
static struct class *keydrv_class;
static struct class_device *keydrv_class_dev;
volatile unsigned long *gpfcon;
volatile unsigned long *gpfdat;
 
volatile unsigned long *gpgcon;
volatile unsigned long *gpgdat;
 
struct pin_desc{
    unsigned int pin;
    unsigned int key_val;
};
 
struct pin_desc pins_desc[4] = {
    {S3C2410_GPF0, 0x01},
    {S3C2410_GPF2, 0x02},
    {S3C2410_GPG3, 0x03},
    {S3C2410_GPG11, 0x04},
};
 
// 键值: 按下时, 0x01, 0x02, 0x03, 0x04 
// 键值: 松开时, 0x81, 0x82, 0x83, 0x84 
static unsigned char key_val;
 
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
 
// 中断事件标志, 中断服务程序将它置1,key_drv_read将它清0 
static volatile int ev_press = 0;
 
 
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
    struct pin_desc * pindesc = (struct pin_desc *)dev_id;
    unsigned int pinval;
 
    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);  // 唤醒休眠的进程 
    
    return IRQ_RETVAL(IRQ_HANDLED);
}
static int key_drv_open(struct inode *inode, struct file *file)
{
    request_irq(IRQ_EINT0, buttons_irq,IRQT_BOTHEDGE,"S2",&pins_desc[0]);
    request_irq(IRQ_EINT2, buttons_irq,IRQT_BOTHEDGE,"S3",&pins_desc[1]);
    request_irq(IRQ_EINT11,buttons_irq,IRQT_BOTHEDGE,"S4",&pins_desc[2]);
    request_irq(IRQ_EINT19,buttons_irq,IRQT_BOTHEDGE,"S5",&pins_desc[3]);
    return 0;
}
 
ssize_t key_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
    if(size != sizeof(key_val))
        return -EINVAL;
 
    // 如果没有按键动作, 休眠 
    wait_event_interruptible(button_waitq, ev_press);
 
    // 如果有按键动作, 返回键值 
    copy_to_user(buf, &key_val, 1);
    
    ev_press = 0;
    
    return 1;
    
}
 
int key_drv_close(struct inode *inode, struct file *file)
{
    free_irq(IRQ_EINT0,  &pins_desc[0]);
    free_irq(IRQ_EINT2,  &pins_desc[1]);
    free_irq(IRQ_EINT11, &pins_desc[2]);
    free_irq(IRQ_EINT19, &pins_desc[3]);
    return 0;
}
 
static struct file_operations key_drv_fops = {
    .owner  =   THIS_MODULE,    // 这是一个宏,推向编译模块时自动创建的__this_module变量 
    .open   =   key_drv_open,     
    .read = key_drv_read,
    .release =  key_drv_close,
};
 
static int key_drv_init(void)
{
    major = register_chrdev(0, "key_drv", &key_drv_fops);
 
    keydrv_class = class_create(THIS_MODULE, "key_drv");
    
    keydrv_class_dev = class_device_create(keydrv_class, NULL, MKDEV(major, 0), NULL, "buttons");
 
    gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
    gpfdat = gpfcon + 1;
 
    gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);
    gpgdat = gpgcon + 1;
 
    return 0;
}
static void key_drv_exit(void)
{
    unregister_chrdev(major, "key_drv");
    class_device_unregister(keydrv_class_dev);
    class_destroy(keydrv_class);
    iounmap(gpfcon);
    iounmap(gpgcon);
    return 0;    
}
 
module_init(key_drv_init);
 
module_exit(key_drv_exit);
 
MODULE_LICENSE("GPL");
 
================================================================================================
测试程序:
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdio.h"
 
int main(int argc, char **argv)
{
    int fd;
    unsigned char key_vals;
 
    fd = open("/dev/buttons", O_RDWR);
    if(fd < 0)
        printf("can't open!\n");
 
    while(1)
    {
        read(fd, &key_vals, 1);
        printf("key_vals = 0x%x\n", key_vals);
    }
    return 0;
}
 

关键字:字符设备驱动  按键中断  程序驱动 

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
浅谈AVR中定时器几种工作模式