#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);
| |