项目要求DSP不跑操作系统, ARM核上linux3.3,在做双核 通信的linux设备驱动时候遇到了一个诡异的问题,只要DSP通过CHIPSIG_INT0触发ARM中断,ARM中的linux内核的其他很多驱动都停止了工作,连自己的led控制驱动都失去了响应,流水灯也失去了闪烁,LCD显示也停止了刷新,但是运行GUI还是可以显示界面,就是界面不能刷新,触摸屏也不懂了。好像是其他驱动都阻塞了!!!!
我的linux设备驱动是这样实现的:使用Tasklet实现软中断,只要DSP的数据一准备好就通过CHIPSIG_INT0触发ARM中断,这时候驱动的tasklet顶半部会立刻响应中断去读取数据,然后调度tasklet的底半部,这样的流程一般是没问题才对, 但是现象就是只要顶半部被触发了,其他驱动就异常了,linux也没有任何提示,而且无法恢复,触发重启内核,但是唯独这个驱动完全正常运行,数据照样读取也不丢帧,还有一个现象是DSP触发一次CHIPSIG_INT0中断,ARM核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。
#include #include#include#include#include#include#include#include#include#include#include #include #include #include #include #include #include "k_linkQueue.h"#include "memory_map.h"#include //for 等待队列api#include //引入其他模块函数和变量extern Ping_Pong_Buffer res_buff;extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列extern void k_linkQueue_release(linkQueue *queue);//释放链队列extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1//设置主从设备号#define PROTOCOL_MAJOR 1#define PROTOCOL_MINOR 0//定义设备驱动的名字或设备节点的名字#define DEVICE_NAME "protocol_driver"//定义全局的循环队列作为数据缓冲区k_linkQueue queue;//寄存器地址映射全局变量unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器//物理内存映射全局变量volatile void *mem_base = NULL;volatile unsigned char *cur_buf_ptr = NULL;volatile unsigned char *data_ready_ptr = NULL;//定义读数据等待队列头,IO阻塞DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);//定义原子变量static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备//定义设备类static struct class *protocol_class;struct cdev *protocol_cdev;dev_t protocol_dev_no;/*定义tasklet和声明底半部函数并关联*/void read_data_tasklet(unsigned long);DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);//将CHIPINT0_tasklet与read_data绑定,传入参数0/*中断处理底半部, 拷贝内存*/void read_data(unsigned long a)[ if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1 [ read_quest = 0; //通过底半部唤醒被阻塞的读取进程 wake_up_interruptible(&wait_queue_head);//唤醒读等待队列 ]]/*中断处理顶半部*/irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)[ //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样 volatile Buffer_Type *next_read; //如果DSP数据已经ready if(*(res_buff.cur_buffer->data_ready) == 1) [ if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer [ next_read = &res_buff.pong_buffer;//下一次中断读pong buffer //printk(KERN_ALERT"read pingn"); ] else [ next_read = &res_buff.ping_buffer;//下一次中断读ping buffer //printk(KERN_ALERT"read pongn"); ] *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer //将数据插入链队列 k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0); //标识位都重置 *(res_buff.cur_buffer->data_ready) = 0; *(res_buff.cur_buffer->data_size) = 0; res_buff.cur_buffer = next_read; ] //清楚中断标识 *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status tasklet_schedule(&CHIPINT0_tasklet);//调度底半部 return IRQ_HANDLED;]//文件打开函数static int protocol_open(struct inode *inode, struct file *file)[ int result = 0; if(!atomic_dec_and_test(&dev_available)) [ atomic_inc(&dev_available); return -EBUSY;//设备已经被打开 ] printk (KERN_ALERT "nprotrol driver openn"); return 0;]//文件释放函数static int protocol_release(struct inode *inode, struct file *filp)[ atomic_inc(&dev_available);//释放设备,原子变量加1 printk (KERN_ALERT "device releasedn"); return 0;]//文件读函数static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)[ int ret = 0; //定义等待队列 DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列 add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列 if(queue.remainNumber == queue.blockNumber)//当前buffer没数据 [ //printk(KERN_ALERT"nbuffer no datan"); //如果是非阻塞方式读取,则直接跳出 if(filp->f_flags & O_NONBLOCK) [ ret = -EAGAIN; goto out; ] //阻塞当前进程,放弃cpu资源 read_quest = 1; __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠 schedule();//调度其他进程运行 if(signal_pending(current)) [ //如果是因为信号被唤醒,则返回到系统调用之前的地方 ret = -ERESTARTSYS; goto out; ] ] //将数据拷贝到用户空间 ret = k_linkQueue_getData(&queue, dst); if(ret == 0) [ //printk(KERN_ALERT"ncopy data to user space failed :%dn", ret); ]out: remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列 set_current_state(TASK_RUNNING);//设置当前进程为运行状态 return ret;]static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)[ return 0;]/*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行open()、release()、ioctl()协同调用时被调用*/static const struct file_operations protocol_fops =[ .owner = THIS_MODULE, .open = protocol_open, .release = protocol_release, .read = protocol_read,// .write = protocol_write, .unlocked_ioctl=protocol_ioctl,];/*设备驱动模块加载函数*/int __init protocol_init(void)[ int ret = 0; int result = 0; //申请注册设备号(动态) ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); if(ret < 0) [ printk(KERN_EMERG "alloc_chrdev_region failedn"); return 0; ] //分配cdev protocol_cdev = cdev_alloc(); if(protocol_cdev == NULL) [ printk(KERN_EMERG "Cannot alloc cdevn"); return 0; ] //初始化cdev cdev_init(protocol_cdev,&protocol_fops); protocol_cdev->owner=THIS_MODULE; //注册cdev cdev_add(protocol_cdev, protocol_dev_no, 1); //创建一个类 protocol_class = class_create(THIS_MODULE, DEVICE_NAME); //创建设备节点 device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME); //申请链式循环队列作为缓冲区DSP数据帧的缓冲区 k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区//映射ARM的核间通讯寄存器 R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4); R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4); //将物理地址映射到内核空间 mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE); //共享内存初始化 SHM_ARM_Init((unsigned char *)mem_base); /*申请中断*//* 参数说明: IRQ_DA8XX_CHIPINT0:要申请的中断号 CHIPINT0_interrupt:向内核登记的中断处理程序(顶半部),为一个回调 IRQF_DISABLED:表明中断处理程序是快速处理程序,快速处理程序被调用时屏蔽所有中断 "DSP Signal":名称 NULL:在中断共享时会用到,这里设置为NULL*/ result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev); if(result != 0) [ if(result == -EINVAL) [ printk(KERN_ALERT "irq request err:-EINVALn"); ] else if(result == -EBUSY) [ printk(KERN_ALERT "irq request err:--EBUSYn"); ] else [ printk(KERN_ALERT "irq request err: unknownn"); ] return result; ] return 0;]/*设备驱动模块卸载函数*/void __exit protocol_exit(void)[ /*释放中断*/ /* 参数详解: IRQ_DA8XX_CHIPINT0:中断号 NULL:void *dev_id,这个参数是中断共享的时候用到的,此驱动不共享中断,因此为NULL */ free_irq(IRQ_DA8XX_CHIPINT0, NULL); //释放帧缓冲的内存 k_linkQueue_release(&queue); //释放寄存器映射 iounmap(R_CHIPSIG); iounmap(R_CHIPSIG_CLR); cdev_del(protocol_cdev); //删除cdev unregister_chrdev_region(protocol_dev_no, 1); //注销设备号 device_destroy(protocol_class, protocol_dev_no); //销毁设备节点 class_destroy(protocol_class); //销毁设备类 printk(KERN_ALERT "exit successn");]//驱动被加载或被卸载自动执行的函数module_init(protocol_init);module_exit(protocol_exit);MODULE_LICENSE("GPL");MODULE_VERSION ("v0.9");MODULE_AUTHOR("None");MODULE_DESCRIPTION("driver");
0
|
5个回答
|
|
|