#include <br />#include <br />#include <br />#include <br />#include <br />#include <br />#include <br />#include <br />#include <br />#include <br />#include <br /><br />MODULE_AUTHOR('XIAOSHOU');<br />MODULE_LICENSE('GPL');<br />MODULE_DESCRIPTION('xiaoshou_IRQ driver test!');<br /><br /><br />//#define DEG //调试<br /><br />#ifdef DEG<br /> #define DEBUG(msg,arg...) printk('kernel_debug message:#>: 'msg,##arg)<br />#else<br /> #define DEBUG(msg,arg...) <br />#endif<br /><br /><br /><br />#define IO_DEL 0<br />#define CMD1 1<br />#define CMD2 2<br />#define DEV_COUNT 1<br />#define DEV_NAME 'IRQ_XSH'<br /><br />#define MAX_BUF_LEN 16<br />#define SIZE MAX_BUF_LEN<br /><br />#define INCBUF(x) (++(x)%(MAX_BUF_LEN))<br />#define DECBUF(x) (--(x)%(MAX_BUF_LEN))<br />struct device_xsh<br />{<br /> unsigned int flag;<br /> unsigned char buf[MAX_BUF_LEN];<br /> unsigned int head,tail;<br /> wait_queue_head_t wq;<br /> struct cdev irq_cdev;<br />};<br /><br />static int minor_num = 0;<br />static int major_num = 0;<br /><br />static struct device_xsh irq_device;<br /><br />static struct class *irq_class;<br /><br />ssize_t irq_read(struct file *filp,char __user *buf,size_t count,loff_t *f_ops);<br />ssize_t irq_write(struct file *filp,const char __user *buf,size_t count,loff_t *f_ops);<br />int irq_open(struct inode *inode,struct file *filp);<br />int irq_release(struct inode *inode,struct file *filp);<br />int irq_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg);<br /><br /><br />static irqreturn_t buttons_irq_isr(int irq,void *dev_id,struct pt_regs *req); //中断服务程序<br />static void do_task_irq(void); //任务队列的执行函数;<br />DECLARE_TASKLET(task_irq, do_task_irq, 0); //中断服务下半部分的任务队列;<br /><br />struct file_operations irq_fops =<br />{<br /> .owner = THIS_MODULE,<br /> .read=irq_read,<br /> .write=irq_write,<br /> .open=irq_open,<br /> .release=irq_release,<br /> .ioctl=irq_ioctl,<br />};<br /><br />static int __init irq_init(void)<br />{<br /> dev_t dev_num=0;<br /> int res;<br /> int err;<br /> unsigned long bitval ;<br /> //###########分配设备号-start####################<br /> if(major_num) //手动分配设备号<br /> {<br /> dev_num=MKDEV(major_num,minor_num);<br /> res=register_chrdev_region(dev_num,DEV_COUNT,DEV_NAME);<br /> }<br /> else //动态分配设备号<br /> {<br /> res=alloc_chrdev_region(&dev_num,minor_num,DEV_COUNT,DEV_NAME);<br /> major_num=MAJOR(dev_num);<br /> }<br /><br /> <br /> if(res<0)<br /> {<br /> DEBUG( 'IRQ alloc_chrdev_region error!!<br />');<br /> return -1;<br /> }<br /> <br /> //#########//申请中断//########################<br /> <br /> set_irq_type(IRQ_EINT3,IRQT_FALLING); //下降沿触发;<br /> res =request_irq(IRQ_EINT3,&buttons_irq_isr,SA_INTERRUPT,DEV_NAME,NULL);<br /> <br /> if(res<0)<br /> {<br /> DEBUG( 'request_irq error_num= %d!!<br />',res);<br /> return -1;<br /> }<br /> //###########分配设备号-end####################<br /> <br /> //############设备初始化#######################<br /> memset(&irq_device,0,sizeof(struct device));<br /> memset(irq_device.buf,0,sizeof(unsigned char)*SIZE);<br /> irq_device.flag=0;<br /> init_waitqueue_head(&(irq_device.wq)); //初始化队列;<br /> <br /> //############注册设备-start#######################<br /> cdev_init(&(irq_device.irq_cdev),&irq_fops);//cdev 结构嵌入一个自己的结构体需初始化<br /> irq_device.irq_cdev.owner=THIS_MODULE;<br /> irq_device.irq_cdev.ops=&irq_fops;<br /> err=cdev_add(&(irq_device.irq_cdev),dev_num,1);<br /> if(err!=0)<br /> {<br /> DEBUG('IRQ cdev_add error!!<br />');<br /> }<br /> irq_class=class_create(THIS_MODULE, 'irq_class'); //udev自动创建/dev/设备文件<br /> class_device_create(irq_class, NULL, dev_num, NULL, DEV_NAME);<br /> <br /> <br /> <br /> DEBUG('insmod char_irq success!<br />');<br /> return 0;<br />}<br />static void __exit irq_exit(void)<br />{<br /> dev_t dev_num;<br /> dev_num=MKDEV(major_num,minor_num);<br /> cdev_del(&(irq_device.irq_cdev));<br /> class_device_destroy(irq_class, dev_num);<br /> class_destroy(irq_class);<br /> free_irq(IRQ_EINT3,NULL);<br /> unregister_chrdev_region(dev_num,1);<br /> DEBUG('rmmod char_irq success!<br />');<br /> return ;<br />}<br /><br />int irq_open(struct inode *inode,struct file *filp)<br />{<br /> struct device *my_device;<br /> try_module_get(THIS_MODULE); //表示此驱动被使用,记数器增加<br /> my_device=container_of(inode->i_cdev,struct device_xsh,irq_cdev);<br /> filp->private_data=my_device;<br /> <br /> <br /> DEBUG('IRQ_char open success!!<br />');<br /> return 0;<br />}<br />int irq_release(struct inode *inode,struct file *filp)<br />{<br /> DEBUG('IRQ_char release success!!<br />');<br /> module_put(THIS_MODULE); //表示此驱动使用完毕,记数器减一<br /> //free_irq(IRQ_EINT3,NULL);<br /> return 0;<br />}<br /><br />ssize_t irq_read(struct file *filp,char __user *buf,size_t count,loff_t *f_ops)<br />{<br /> int err;<br /> char tmp;<br />retry:<br /> if(irq_device.head!=irq_device.tail)<br /> {<br /> tmp=irq_device.buf[irq_device.tail];<br /> err=copy_to_user(buf,&tmp,1);<br /> DEBUG('irq_device.buf=0x%x<br />',irq_device.buf[irq_device.tail]);<br /> if(err!=0)<br /> {<br /> DEBUG('irq_char copy_to_user error!!<br />');<br /> return 0;<br /> }<br /> irq_device.tail=INCBUF(irq_device.tail);<br /> return 1;<br /> }else<br /> {<br /> if(filp->f_flags & O_NONBLOCK)<br /> {<br /> return -EAGAIN;<br /> }<br /> wait_event_interruptible(irq_device.wq,irq_device.flag);<br /> irq_device.flag=0;<br /> if(signal_pending(current))<br /> {<br /> printk('rturn -ERESTARTSYS<br />');<br /> return -ERESTARTSYS;<br /> }<br /> goto retry;<br /> }<br /> <br /><br /> return 1;<br />}<br /><br />ssize_t irq_write(struct file *filp,const char __user *buf,size_t count,loff_t *f_ops)<br />{<br /> int err;<br /> memset(irq_device.buf,0,sizeof(char)*SIZE);<br /> err=copy_from_user(irq_device.buf,buf,count);<br /> if (err!=0)<br /> {<br /> DEBUG('irq_char copy_from_user error!!<br />');<br /> return 0;<br /> }<br /> return count;<br />}<br /><br />int irq_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg)<br />{<br /> switch(cmd)<br /> {<br /> case IO_DEL:<br /> <br /> DEBUG( 'ioctl IO_DEL success!');<br /> break;<br /> case CMD1:<br /> DEBUG( 'kernel_debug : IO CMD1=%d<br />',CMD1);<br /> break;<br /> case CMD2:<br /> DEBUG( 'kernel_debug : IO CMD2=%d<br />',CMD2);<br /> break;<br /> default:<br /> return;<br /><br /> }<br />}<br />static irqreturn_t buttons_irq_isr(int irq,void *dev_id,struct pt_regs *req)<br />{ <br /> DEBUG( 'IRQ_ISR <br />');<br /> tasklet_schedule(&task_irq); //任务调度中断下半部分服务程序;<br /> return IRQ_HANDLED; //返回中断已经获得;<br />}<br />static void do_task_irq(void)<br />{<br /> irq_device.buf[irq_device.head]='K';<br /> DEBUG('irq_device.head=%d<br />',irq_device.head);<br /> DEBUG('irq_device.buf=0x%x<br />',irq_device.buf[irq_device.head]);<br /> irq_device.head=INCBUF(irq_device.head);<br /> irq_device.flag=1;<br /> wake_up_interruptible(&(irq_device.wq));<br /> <br /> //DEBUG( 'do_task_irq <br />');<br />}<br />module_init(irq_init);<br />module_exit(irq_exit);<br /> <br /> <br /> |
|