/* ========================================================================== */
/*??????????????????????????????????????????????????????????????????????????? */
/*?? Filename.c?????????????????????????????????????????????????????????????? */
/*?? (c) 2001 Author? Zhang Haibo???????????????????????????????????????????? */
/*??????????????????????????????????????????????????????????????????????????? */
/*?? Description? driver program with interrupt and poll????????????????????? */
/*??????????????????????????????????????????????????????????????????????????? */
/* ========================================================================== */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
static struct class *cpld_class;????????????????? //自動創建設備文件時需要先創建類
static struct class_device *cpld_class_dev;?????? //再創建驅動
static DECLARE_WAIT_QUEUE_HEAD(eint1_waitq);????? //將中斷放入等待隊列
static struct fasync_struct *eint1_async;???????? //
static volatile int ev_eint1 = 0;???????????????? //中斷標志,為1表示中斷發生,在中斷服務程序里置1
volatile unsigned long *cpld_data = NULL;???????? //CPLD的物理地址映射的虛擬地址指針? 0x08000000
volatile unsigned long *gpfcon = NULL;??????????? //GPF控制寄存器
volatile unsigned long *gpfdat = NULL;??????????? //GPF數據寄存器,0位為使能位
static irqreturn_t eint1_irq(int irq, void *dev_id) //中斷服務程序
{
??? ev_eint1 = 1;?????????????????????????????????? //中斷標志位置1
??? *gpfdat &= ~(1<<2);???????????????????????????? //進入中斷GPF2清0
??? wake_up_interruptible(&eint1_waitq);??????????? //喚醒休眠的進程
??? kill_fasync (&eint1_async, SIGIO, POLL_IN);???? //產生中斷后,驅動向應用程序發送信號?????
??? return IRQ_RETVAL(IRQ_HANDLED);
}
static int cpld_drv_open(struct inode *inode, struct file *file)
{
??? request_irq(IRQ_EINT1,? eint1_irq, IRQ_TYPE_EDGE_FALLING, "EINT1", 1);//注冊中斷:中斷號,中斷程序入口,中斷方式,中斷名,代號
??? return 0;
}
?
static ssize_t cpld_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
??? int val;
??? *gpfdat &=~(1<<0);??????????????? //使能位置0,使能CPLD產生PWM,計數器開始計數
??? copy_from_user(&val, buf, count); //產生PWM的值從用戶空間傳入
??? iowrite16(val,cpld_data);???????? //寫入CPLD
??? return 0;
}
?
static ssize_t cpld_drv_read(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
??? int val;
??? wait_event_interruptible(eint1_waitq, ev_eint1);? //若無中斷產生,即ev_eint1=0,則休眠
??? val=ioread16(cpld_data);????????????????????????? //若中斷產生,則從CPLD讀取數據,即編碼器值
??? copy_to_user(buf,&val,count);???????????????????? //將讀取值傳遞到用戶空間
??? ev_eint1 = 0;???????????????????????????????????? //中斷標志清0
??? *gpfdat |= (1<<2);?????????????????????????????? //中斷讀數后,GPF2置1
??? return 0;
}
static unsigned cpld_drv_poll(struct file *file, poll_table *wait)
{
? ?unsigned int mask = 0;
? ?poll_wait(file, &eint1_waitq, wait);?????? //不會立即休眠
? ?if (ev_eint1)
? ?mask |= POLLIN | POLLRDNORM;?????????????? //若產生中斷,mask賦值,表示有數據可讀
? ?return mask;
}
?
static int cpld_drv_fasync (int fd, struct file *filp, int on)
{
?//printk("driver: cpld_drv_fasync\n");
?return fasync_helper (fd, filp, on, &eint1_async);
}
int cpld_drv_close(struct inode *inode, struct file *file)
{
??? free_irq(IRQ_EINT1, 1);?????? //釋放中斷??
??? return 0;
}
?
static struct file_operations cpld_drv_fops = {
??? .owner??? = THIS_MODULE,??????????????????
??? .write??? = cpld_drv_write,
??? .read???? = cpld_drv_read,
??? .open???? = cpld_drv_open,
??? .release? = cpld_drv_close,
??? .poll???? = cpld_drv_poll,
??? .fasync?? = cpld_drv_fasync,??
};
?
int major;
static int cpld_drv_init(void)
{
??? major = register_chrdev(0, "cpld_drv", &cpld_drv_fops);???????????????? //注冊設備
??? cpld_class = class_create(THIS_MODULE, "cplddrv");????????????????????? //創建類
??? cpld_class_dev = device_create(cpld_class, NULL, MKDEV(major, 0), NULL, "cpld_drv"); //自動創建設備文件 /dev/cpld_drv
??? cpld_data = (volatile unsigned long *)ioremap(0x08000000,4);??????????? //映射CPLD物理地址到虛擬地址
??? gpfcon = (volatile unsigned long *)ioremap(0x56000050, 8);????????????? //映射GPF寄存器物理地址到虛擬地址
??? gpfdat = gpfcon+1;
??? *gpfcon &=~((0x3<<0) | (0x3<<(2*2)));
??? *gpfcon |=((0x1<<0) | (0x01<<(2*2)));???? //設置GPF0、2為輸出
??? *gpfdat |=0x1;????????? //將使能位置1,加載驅動時CPLD不輸出PWM
??? printk("cpld_drv initialized!\n");
??? return 0;
}
?
static void cpld_drv_exit(void)
{
??? *gpfdat |=0x1;????????? //將使能位置1,卸載驅動后CPLD不輸出PWM
??? unregister_chrdev(major, "cpld_drv"); //注銷驅動
??? device_unregister(cpld_class_dev);??? //注銷設備
??? class_destroy(cpld_class);??????????? //注銷類
??? iounmap(cpld_data);?????????????????? //取消映射
??? iounmap(gpfcon);
}
?
module_init(cpld_drv_init);
module_exit(cpld_drv_exit);
?
MODULE_LICENSE("GPL");
評論
查看更多