前言
一个项目中使用了赛灵思的FPGA,需要fpga这边和arm这边进行数据通讯,通讯方式使用的是一段fpga和arm共享的ddr内存,把这块内存做了一个fifo,并通过中断出发,我在arm这边实现一个驱动来接收处理中断,然后读取fifo.
驱动的结构体
c
struct ddr_fifo_dev {
int index;
dev_t devid;
struct cdev cdev;
struct miscdevice miscdev;
struct device * device;
struct device_node * nd;
char name[64];
struct fasync_struct * async_queue;
wait_queue_head_t r_wait;
struct file * file;
int openflag;
int irq_id;
void __iomem * regbase;
phys_addr_t physreg;
size_t physreglen;
phys_addr_t rxfifostart;
size_t rxfifolen;
phys_addr_t txfifostart;
size_t txfifolen;
atomic_t irq_flag;
};
poll处理函数
c
static unsigned int ddr_fifo_poll(struct file * file, struct poll_table_struct * poll_table)
{
unsigned int mask = 0;
struct ddr_fifo_dev * df_devdata =
container_of(file->private_data, struct ddr_fifo_dev, miscdev);
//添加这个文件结构到等待队列
poll_wait(file, &df_devdata->r_wait, poll_table);
if (atomic_read(&df_devdata->irq_flag)==0) {
//没有数据,这个接口返回0,等待内核的下次调用
mask = 0;
}else{
//有数据,返回POLLIN | POLLRDNORM后,调用poll的进程会被内核唤醒
atomic_dec(&df_devdata->irq_flag);
mask = POLLIN | POLLRDNORM;
dev_dbg(df_devdata->device, "POLLIN irq_flag=%d\n",atomic_read(&df_devdata->irq_flag));
}
return mask;
}
中断处理函数
- 每次进入中断后,操作寄存器清除中断标记
- 唤醒等待队列上的进程
- 原子计数加一
c
static irqreturn_t irq_interrupt(int irq, void * dev_id)
{
struct ddr_fifo_dev * df_devdata = (struct ddr_fifo_dev *)dev_id;
ddr_rxfifo_irq_clear(df_devdata->regbase);
wake_up_interruptible(&df_devdata->r_wait);
atomic_inc(&df_devdata->irq_flag);
return IRQ_HANDLED;
}