打印
[ZLG-ARM]

S3C2410中断按键驱动

[复制链接]
825|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
reeper|  楼主 | 2009-4-9 15:08 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

MODULE_AUTHOR('XIAOSHOU');
MODULE_LICENSE('GPL');
MODULE_DESCRIPTION('xiaoshou_IRQ driver  test!');


//#define DEG        //调试

#ifdef DEG
    #define DEBUG(msg,arg...)     printk('kernel_debug message:#>:  'msg,##arg)
#else
    #define DEBUG(msg,arg...) 
#endif



#define IO_DEL 0
#define CMD1    1
#define CMD2    2
#define DEV_COUNT 1
#define DEV_NAME 'IRQ_XSH'

#define MAX_BUF_LEN            16
#define SIZE                     MAX_BUF_LEN

#define INCBUF(x)                (++(x)%(MAX_BUF_LEN))
#define DECBUF(x)                (--(x)%(MAX_BUF_LEN))
struct device_xsh
{
    unsigned int flag;
    unsigned char buf[MAX_BUF_LEN];
    unsigned int head,tail;
    wait_queue_head_t wq;
    struct cdev irq_cdev;
};

static int minor_num = 0;
static int major_num = 0;

static struct device_xsh irq_device;

static struct class *irq_class;

ssize_t irq_read(struct file *filp,char __user *buf,size_t count,loff_t *f_ops);
ssize_t irq_write(struct file *filp,const char __user *buf,size_t count,loff_t *f_ops);
int irq_open(struct inode *inode,struct file *filp);
int irq_release(struct inode *inode,struct file *filp);
int irq_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg);


static irqreturn_t buttons_irq_isr(int irq,void *dev_id,struct pt_regs *req);    //中断服务程序
static void do_task_irq(void);                                        //任务队列的执行函数;
DECLARE_TASKLET(task_irq, do_task_irq, 0);                            //中断服务下半部分的任务队列;

struct file_operations irq_fops =
{
    .owner = THIS_MODULE,
    .read=irq_read,
    .write=irq_write,
    .open=irq_open,
    .release=irq_release,
    .ioctl=irq_ioctl,
};

static int __init irq_init(void)
{
    dev_t dev_num=0;
    int res;
    int err;
    unsigned long bitval ;
    //###########分配设备号-start####################
    if(major_num)                            //手动分配设备号
    {
        dev_num=MKDEV(major_num,minor_num);
        res=register_chrdev_region(dev_num,DEV_COUNT,DEV_NAME);
    }
    else                                    //动态分配设备号
    {
        res=alloc_chrdev_region(&dev_num,minor_num,DEV_COUNT,DEV_NAME);
        major_num=MAJOR(dev_num);
    }

    
    if(res<0)
    {
        DEBUG( 'IRQ alloc_chrdev_region error!!
');
        return -1;
    }
        
    //#########//申请中断//########################
    
    set_irq_type(IRQ_EINT3,IRQT_FALLING);            //下降沿触发;
    res =request_irq(IRQ_EINT3,&buttons_irq_isr,SA_INTERRUPT,DEV_NAME,NULL);
    
    if(res<0)
    {
        DEBUG( 'request_irq error_num= %d!!
',res);
        return -1;
    }
    //###########分配设备号-end####################
    
    //############设备初始化#######################
    memset(&irq_device,0,sizeof(struct device));
    memset(irq_device.buf,0,sizeof(unsigned char)*SIZE);
    irq_device.flag=0;
    init_waitqueue_head(&(irq_device.wq));                    //初始化队列;
    
    //############注册设备-start#######################
    cdev_init(&(irq_device.irq_cdev),&irq_fops);//cdev 结构嵌入一个自己的结构体需初始化
    irq_device.irq_cdev.owner=THIS_MODULE;
    irq_device.irq_cdev.ops=&irq_fops;
    err=cdev_add(&(irq_device.irq_cdev),dev_num,1);
    if(err!=0)
    {
        DEBUG('IRQ cdev_add error!!
');
    }
    irq_class=class_create(THIS_MODULE, 'irq_class');    //udev自动创建/dev/设备文件
    class_device_create(irq_class, NULL, dev_num, NULL, DEV_NAME);
    
    
    
    DEBUG('insmod char_irq success!
');
    return 0;
}
static void __exit irq_exit(void)
{
    dev_t dev_num;
    dev_num=MKDEV(major_num,minor_num);
    cdev_del(&(irq_device.irq_cdev));
    class_device_destroy(irq_class,  dev_num);
    class_destroy(irq_class);
    free_irq(IRQ_EINT3,NULL);
    unregister_chrdev_region(dev_num,1);
    DEBUG('rmmod char_irq success!
');
    return ;
}

int irq_open(struct inode *inode,struct file *filp)
{
    struct device *my_device;
    try_module_get(THIS_MODULE);                //表示此驱动被使用,记数器增加
    my_device=container_of(inode->i_cdev,struct device_xsh,irq_cdev);
    filp->private_data=my_device;
    
    
    DEBUG('IRQ_char open success!!
');
    return 0;
}
int irq_release(struct inode *inode,struct file *filp)
{
    DEBUG('IRQ_char release success!!
');
    module_put(THIS_MODULE);                    //表示此驱动使用完毕,记数器减一
    //free_irq(IRQ_EINT3,NULL);
    return 0;
}

ssize_t irq_read(struct file *filp,char __user *buf,size_t count,loff_t *f_ops)
{
    int err;
    char tmp;
retry:
    if(irq_device.head!=irq_device.tail)
    {
        tmp=irq_device.buf[irq_device.tail];
        err=copy_to_user(buf,&tmp,1);
        DEBUG('irq_device.buf=0x%x
',irq_device.buf[irq_device.tail]);
        if(err!=0)
        {
            DEBUG('irq_char copy_to_user error!!
');
            return 0;
        }
        irq_device.tail=INCBUF(irq_device.tail);
        return 1;
    }else
    {
        if(filp->f_flags & O_NONBLOCK)
        {
            return -EAGAIN;
        }
        wait_event_interruptible(irq_device.wq,irq_device.flag);
        irq_device.flag=0;
        if(signal_pending(current))
        {
            printk('rturn -ERESTARTSYS
');
            return -ERESTARTSYS;
        }
        goto retry;
    }
    

    return 1;
}

ssize_t irq_write(struct file *filp,const char __user *buf,size_t count,loff_t *f_ops)
{
    int err;
    memset(irq_device.buf,0,sizeof(char)*SIZE);
    err=copy_from_user(irq_device.buf,buf,count);
    if (err!=0)
    {
        DEBUG('irq_char copy_from_user error!!
');
        return 0;
    }
    return count;
}

int irq_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg)
{
    switch(cmd)
    {
        case IO_DEL:
            
            DEBUG( 'ioctl IO_DEL success!');
            break;
        case CMD1:
            DEBUG( 'kernel_debug : IO  CMD1=%d
',CMD1);
            break;
        case CMD2:
            DEBUG( 'kernel_debug : IO  CMD2=%d
',CMD2);
            break;
        default:
            return;

    }
}
static irqreturn_t buttons_irq_isr(int irq,void *dev_id,struct pt_regs *req)
{    
    DEBUG( 'IRQ_ISR 
');
    tasklet_schedule(&task_irq);                //任务调度中断下半部分服务程序;
    return IRQ_HANDLED;                    //返回中断已经获得;
}
static void do_task_irq(void)
{
    irq_device.buf[irq_device.head]='K';
    DEBUG('irq_device.head=%d
',irq_device.head);
    DEBUG('irq_device.buf=0x%x
',irq_device.buf[irq_device.head]);
    irq_device.head=INCBUF(irq_device.head);
    irq_device.flag=1;
    wake_up_interruptible(&(irq_device.wq));
    
    //DEBUG( 'do_task_irq 
');
}
module_init(irq_init);
module_exit(irq_exit);
 
   

相关帖子

沙发
zcying| | 2009-4-9 15:09 | 只看该作者

linux模块,不是裸机代码。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

139

主题

185

帖子

0

粉丝