2440核心板+自制地板+外挂FPGA。
FPGA片选使用nGCS1,OE和WE挂在2440的OE和WE上,中断采用EINT4. FPGA数据准备好后发中断通知ARM读取。
现在的问题是:
1、在驱动中能检测到中断,在驱动中用ioremap进行了内存映射,然后copy_to_user但感觉数据不对,显示出来的图像是乱的(可以说不成其为图)
2、不知道FPGA接在nGCS1上,是不是使用0x08000000起始的这段地址?
3、如果采用中断方式该如何实现?我使用
dmabuf = dma_alloc_coherent(NULL, PIC_DATA_SIZE, dmaphys, GFP_KERNEL)函数时老是报错
驱动源码如下:
/*======================================================================
A fpgadrv driver as a char device drivers
The initial developer of the original code is wangxpin
<wangxpin_cq@126.cn>. qq:468077776 . All Rights Reserved.
======================================================================*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <asm/io.h> //readb readw
#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/ioport.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <mach/regs-gpio.h>
#define irq_num IRQ_EINT4 //(外部中断4)
#define EXT_FALLING_EDGE 2
#define fpgadrv_SIZE 0x100000 /*全局内存最大0x100000字节*/
#define MEM_CLEAR 0x1 /*清0全局内存*/
#define fpgadrv_MAJOR 260 /*预设的fpgadrv的主设备号*/
//
#define FPGA_BASE_PHY_ADDR 0x08000000 //nGCS1
#define FPGA_MAXADDR 0x080FFFFE //20 bit addr
#define PIC_OFFSET 0xE0000 //
#define PIC_DATA_SIZE 384*288*2
/*fpgadrv设备结构体*/
struct fpgadrv_dev
{
struct cdev cdev; /*cdev结构体*/
unsigned char mem[fpgadrv_SIZE]; /*全局内存*/
};
static char drv_name[] = "fpgadrv";
static struct resource *fpga_mem;
static void __iomem *fpga_base; //FPGA线性地址
static int fpgadrv_major = fpgadrv_MAJOR;
struct fpgadrv_dev *fpgadrv_devp; /*设备结构体指针*/
spinlock_t pgd_lock = SPIN_LOCK_UNLOCKED;
wait_queue_head_t wq; /* global variable */
DECLARE_WAIT_QUEUE_HEAD (wq);
static int flag=0;
//设置中断处理程序*/
static irqreturn_t irq_handle(int irq, void *devid)
{
if(flag == 0)
{
flag = 1;
wake_up_interruptible(&wq);
}
return IRQ_HANDLED;
}
/*EINT4中断模式设置*/
static void init_interrupt(void)
{
int ret;
// printk(KERN_INFO "init_interrupt::interrupt!\n");
s3c2410_gpio_cfgpin(S3C2410_GPF4,S3C2410_GPF4_EINT4);
set_irq_type(IRQ_EINT4,EXT_FALLING_EDGE);//设置中断4 触发方式
disable_irq(IRQ_EINT4);
enable_irq(IRQ_EINT4);
ret=request_irq(IRQ_EINT4,irq_handle,IRQF_SHARED,drv_name,1);//注册中断4
if(ret<0)
{
printk(KERN_INFO "init_interrupt::IRQ %d can not request\n",IRQ_EINT4);
return ;
}
init_waitqueue_head(&wq);
}
/*文件打开函数*/
int fpgadrv_open(struct inode *inode, struct file *filp)
{
/*将设备结构体指针赋值给文件私有数据指针*/
filp->private_data = fpgadrv_devp;
fpga_base =ioremap_nocache(FPGA_BASE_PHY_ADDR+PIC_OFFSET,PIC_DATA_SIZE*2);//verify mmap corrected
if(fpga_base == NULL)
{
printk(KERN_INFO "fpgadrv_open::remapped FPGA address error\n");
return -1;
}
else
printk(KERN_INFO "remapped FPGA address= 0x%8x\n", (int)fpga_base);
init_interrupt();
//////
return 0;
}
/*文件释放函数*/
int fpgadrv_release(struct inode *inode, struct file *filp)
{
iounmap(fpga_base);
return 0;
}
/* ioctl设备控制函数 */
static int fpgadrv_ioctl(struct inode *inodep, struct file *filp, unsigned
int cmd, unsigned long arg)
{
struct fpgadrv_dev *dev = filp->private_data;/*获得设备结构体指针*/
switch (cmd)
{
case MEM_CLEAR:
memset(dev->mem, 0, fpgadrv_SIZE);
printk(KERN_INFO "fpgadrv is set to zero\n");
break;
default:
return - EINVAL;
}
return 0;
}
/*读函数*/
static ssize_t fpgadrv_read(struct file *filp, char __user *buf, size_t size,
loff_t *ppos)
{
unsigned long flags; //能从中断上下文中被调用
//printk(KERN_ALERT "FPGA line address= 0x%8x\n", (int)fpga_base);
wait_event_interruptible(wq,flag==1);
flag = 0;
spin_lock_irqsave(&pgd_lock, flags);//加锁
copy_to_user(buf,(char *)fpga_base,size);
spin_unlock_irqrestore(&pgd_lock, flags);//解锁
return size;
}
/*写函数*/
static ssize_t fpgadrv_write(struct file *filp, const char __user *buf,
size_t size, loff_t *ppos)
{
return ret;
}
static loff_t fpgadrv_llseek(struct file *filp, loff_t offset, int orig)
{
return 0;
}
static const struct file_operations fpgadrv_fops =
{
.owner = THIS_MODULE,
.llseek = fpgadrv_llseek,
.read = fpgadrv_read,
.write = fpgadrv_write,
.ioctl = fpgadrv_ioctl,
.open = fpgadrv_open,
.release = fpgadrv_release,
};
static void fpgadrv_setup_cdev(struct fpgadrv_dev *dev, int index)
{
int err, devno = MKDEV(fpgadrv_major, index);
cdev_init(&dev->cdev, &fpgadrv_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &fpgadrv_fops;
err = cdev_add(&dev->cdev, devno, 1);
if (err)
printk(KERN_NOTICE "Error %d adding LED%d", err, index);
else
printk(KERN_NOTICE "fpgadrv_setup_cdev success--cdev_add");
}
/*设备驱动模块加载函数*/
int fpgadrv_init(void)
{
int result;
dev_t devno = MKDEV(fpgadrv_major, 0);
/* 申请设备号*/
if (fpgadrv_major)
result = register_chrdev_region(devno, 1, drv_name);
else /* 动态申请设备号 */
{
result = alloc_chrdev_region(&devno, 0, 1, drv_name);
fpgadrv_major = MAJOR(devno);
}
if (result < 0)
{
printk(KERN_NOTICE "alloc_chrdev_region error");
return result;
}
/* 动态申请设备结构体的内存*/
fpgadrv_devp = kmalloc(sizeof(struct fpgadrv_dev), GFP_KERNEL);
if (!fpgadrv_devp) /*申请失败*/
{
result = - ENOMEM;
printk(KERN_NOTICE "kmalloc(sizeof(struct fpgadrv_dev), GFP_KERNEL) error");
goto fail_malloc;
}
memset(fpgadrv_devp, 0, sizeof(struct fpgadrv_dev));
fpgadrv_setup_cdev(fpgadrv_devp, 0);
fpga_mem=request_mem_region(FPGA_BASE_PHY_ADDR, fpgadrv_SIZE, "FPGAMEM");//向内核申请内存资源
if (fpga_mem == NULL) {
printk("failed to get fpga_mem memory region\n");
return -ENOENT;
}
printk("request_mem_region success\n");
return 0;
fail_malloc: unregister_chrdev_region(devno, 1);
return result;
}
/*模块卸载函数*/
void fpgadrv_exit(void)
{
cdev_del(&fpgadrv_devp->cdev); /*注销cdev*/
kfree(fpgadrv_devp); /*释放设备结构体内存*/
release_resource(fpga_mem);
kfree(fpga_mem) ;
disable_irq(IRQ_EINT4);
free_irq(IRQ_EINT4,NULL);
unregister_chrdev_region(MKDEV(fpgadrv_major, 0), 1); /*释放设备号*/
}
MODULE_AUTHOR("wangxpin");
MODULE_LICENSE("Dual BSD/GPL");
module_param(fpgadrv_major, int, S_IRUGO);
module_init(fpgadrv_init);
module_exit(fpgadrv_exit);
|