Chinaunix首页 | 论坛 | 博客
  • 博客访问: 318045
  • 博文数量: 68
  • 博客积分: 1501
  • 博客等级: 上尉
  • 技术积分: 1010
  • 用 户 组: 普通用户
  • 注册时间: 2008-12-30 09:52
文章分类

全部博文(68)

文章存档

2010年(1)

2009年(67)

我的朋友

分类:

2009-02-03 14:32:28

S3C2410中断按键驱动:
#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!!\n");
        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!!\n",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!!\n");
    }
    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!\n");
    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!\n");
    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!!\n");
    return 0;
}
 int irq_release(struct inode *inode,struct file *filp)
{
    DEBUG("IRQ_char release success!!\n");
    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\n",irq_device.buf[irq_device.tail]);
        if(err!=0)
        {
            DEBUG("irq_char copy_to_user error!!\n");
            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\n");
            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!!\n");
        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\n",CMD1);
            break;
        case CMD2:
            DEBUG( "kernel_debug : IO  CMD2=%d\n",CMD2);
            break;
        default:
            return;

    }
}
static irqreturn_t buttons_irq_isr(int irq,void *dev_id,struct pt_regs *req)
{   
    DEBUG( "IRQ_ISR \n");
    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\n",irq_device.head);
    DEBUG("irq_device.buf=0x%x\n",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 \n");
}
module_init(irq_init);
module_exit(irq_exit);

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