本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑 8 n# p I* M* e
3 Y. f4 @& y" J
项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略6 S% Y: O9 Z( v( W8 x
- ( `7 [, e# l# _1 N& Z$ N6 c, n
- //引入其他模块函数和变量
[0 t# R$ m7 A8 y- {* R, b - extern Ping_Pong_Buffer res_buff;# k9 a8 o- W- X
- / X% f( H0 z8 J4 j1 Y
- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列
2 t2 J; ?* X( n r3 I% l9 V - extern void k_linkQueue_release(linkQueue *queue);//释放链队列
. f- q% q w, ^ - extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据4 E0 p/ E3 k: f2 i( }. T$ S$ i* _9 a
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据
7 X3 I S) n' ^2 a- {/ s5 n - + M! e' f( X. \& ]+ x+ I& ]# j, r# Q
- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化
# g) L, [$ M# L' A6 l
# h+ c! e, a" P7 Y) k+ _4 J M+ g- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1
- W+ d8 U G6 v - //设置主从设备号
" b* T- I% p! a7 C k0 a# d/ e - #define PROTOCOL_MAJOR 18 E ?- {) Z! _. c1 L+ q. l8 y
- #define PROTOCOL_MINOR 0
' M0 n( K0 j, z* C) s
7 g9 ?1 Z. W. L4 U- 2 U5 x' I: N7 b4 v/ s
- # u+ V& s: e4 |$ ?3 x0 N) d8 c
- //定义设备驱动的名字或设备节点的名字
" D: q! b# `" y8 l7 l3 w' J - #define DEVICE_NAME "protocol_driver"
# x1 _/ C' F. J9 a& {* u# K+ p
/ b! G, b; L1 I( b- s' w& {8 R- , Q; R. ~. _5 H3 Y ]) s
- //定义全局的循环队列作为数据缓冲区8 d% @* r+ T) E& t B& P8 f
- k_linkQueue queue;) I1 j& P1 U# W
) r* u' Y( W( ^) s8 Q1 Y- //寄存器地址映射全局变量 Q8 R4 Q R0 c5 R2 @8 o8 u: j" m
- unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器
( ]8 m( N) U: X" R+ c$ s- P - unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器
/ u$ _, ^* N2 j2 s! @ g/ N - 4 T* A1 S9 N K. C) _
- //物理内存映射全局变量1 K0 E7 u7 {7 r. F0 L
- volatile void *mem_base = NULL;3 ]/ l" L- h' K
- volatile unsigned char *cur_buf_ptr = NULL;+ q; Y9 w7 i) U; L2 D; @
- volatile unsigned char *data_ready_ptr = NULL;
# i+ w5 U6 R+ I; K: y' |! P
* q" s1 W; i! v9 o+ V: m3 b9 a
, A/ I& v1 _1 w+ K6 M3 {- $ h: G/ d7 U* ]. |4 q# J9 A
- //定义读数据等待队列头,IO阻塞
6 `) A& D9 I. b- N; D - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);
3 G) ^- F/ J8 A1 p - 7 o( a! s& u' l# T7 j% o
- //定义原子变量
3 Y* K0 A! C$ [" J1 y0 x. { - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备, k$ o3 C/ l0 A: G0 [1 @
- # j, R/ u6 N- M0 F' J
- ^& h4 P% a. Q9 `, M" ~/ \8 H- //定义设备类
, G' o7 C1 |1 w4 ^6 R: o - static struct class *protocol_class;
$ g2 n; [$ Y- v1 O6 H - struct cdev *protocol_cdev;
5 T! v9 c" }# M: _ - dev_t protocol_dev_no;$ o0 k' ^( y! }/ d
- 5 D+ N) A+ ?$ \
- /*定义tasklet和声明底半部函数并关联*/, M' {% v; [; f2 ]" T* B0 r) n
- void read_data_tasklet(unsigned long);
1 M/ H! B f) z, @ - 7 R& I) o, _" X1 E/ @
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
; C" L& f4 l* S& U. `. `& n - //将CHIPINT0_tasklet与read_data绑定,传入参数0
( O# u& \; z( ~( l
( z* N" W* L% H! r: n2 i- /*中断处理底半部, 拷贝内存*/ d h& c% b( [6 g7 S0 K
- void read_data(unsigned long a)
5 c( N- L( e( m& ] - {% {0 y, {; s6 E3 h. ]$ I" X
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1% m; ^) J2 n4 [# ?
- {0 ?+ s6 w `" z4 M6 ~8 R. Z
- read_quest = 0;
6 y' X/ I$ _" I, k - wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
9 H7 y( k) L& g - }9 ?) r. l+ p2 q. w' {8 B8 V' n$ {( R* l
) J% t6 a& J& T: w5 q- }2 l3 b2 W( G+ F; o" s6 X0 s
- - L. @- u b( V8 u2 Q
- /*中断处理顶半部*/
8 S" j3 h/ q2 z" M3 | - irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)# C$ l& g$ U5 r/ I) e6 o) _
- {
9 c+ v! c8 h3 C) C/ n - //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样$ O T8 L3 B( Y7 } ]+ q
- volatile Buffer_Type *next_read;: D7 w& T* p% ]2 M
- //如果DSP数据已经ready
' \. a0 b" L* |4 Q6 ?, C; ]: ^ - if(*(res_buff.cur_buffer->data_ready) == 1)
1 ?5 n4 H2 |: e) I+ Y; U) A1 X" B - {+ g/ g( E, d' \ h7 N
- if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer' V& z" W; x# B- ?+ H
- {# b# }( }( r6 K2 C+ D6 b! T+ K
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer$ ?& n7 n# T) a* ~/ t; k& q
- //printk(KERN_ALERT"read ping\n");
, ?4 L% G3 f/ G! n, Y6 _) z1 t - }
' @, j0 c9 O. V4 L - else
1 V* {! S/ y! y# w4 J6 e - {4 K8 ~8 T# H+ m) {
- next_read = &res_buff.ping_buffer;//下一次中断读ping buffer
0 J. V. A. m; Z - //printk(KERN_ALERT"read pong\n");
# A; ?9 d! w" k+ \& _( l - }' Y3 }) |/ R7 t/ p
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer. n' U/ E$ c" L2 Z! r( W
- //将数据插入链队列7 `9 E3 D) p/ O3 ~, k
- k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);
* p3 e& h4 D: A' Q - //标识位都重置
^6 W5 R4 B, X8 A - *(res_buff.cur_buffer->data_ready) = 0;% P O/ x2 u- F3 m
- *(res_buff.cur_buffer->data_size) = 0;; f3 P0 M: \/ x- P! f
- res_buff.cur_buffer = next_read;: Y% j- }& W4 m# W
- }
% T0 d1 Q4 d3 K/ ~# @2 f" P - //清楚中断标识: a3 C! }1 s! R% Z# d" I
- *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status# r; a) t z! d- L2 v, b( q$ F
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部 / M2 m/ b5 y. A+ T
1 G1 {9 v& S% R: c. k( ?' Q# O0 C- 8 T* d( u( P0 r% C" C
- return IRQ_HANDLED;& ?) K" E* X5 R: u" a3 [$ E
- 3 q4 p) D- p) N N
- }
' A( A" }1 i8 Z7 z
, f% Z: M+ E3 B- //文件打开函数
L$ O3 N/ \2 s k+ W4 O7 H - static int protocol_open(struct inode *inode, struct file *file)
i' o9 b& _; K, `' N% l t - {/ ~; `% k5 Q4 W' {, v; @6 Z* L* G' f
- int result = 0;4 q$ n) g% d, B: G
- if(!atomic_dec_and_test(&dev_available))
/ ^ U9 v' s- D9 D, W' A - {" U2 k. C1 w+ c! P
- atomic_inc(&dev_available);, n% k, L1 w3 N1 m0 @
- return -EBUSY;//设备已经被打开9 [$ C2 ^* Y! i! ?" ^
- }" f4 e0 s2 T+ E2 T2 H
- printk (KERN_ALERT "\nprotrol driver open\n");' a& M2 }: d7 D2 P0 r$ R
- return 0;
& j: L0 R0 H# I, { - }2 @) _. L% @0 F9 F1 v& E6 X) d1 B3 f
- : \) [) g# f4 [# y# X) V
- //文件释放函数
' V5 G% U7 b$ y q4 y4 x$ P - static int protocol_release(struct inode *inode, struct file *filp)
$ d! F2 r) O; } - {& K4 _: Z3 g% H9 _, U7 c) q. Y
- atomic_inc(&dev_available);//释放设备,原子变量加1
% k2 Y1 e( f8 J1 v z - printk (KERN_ALERT "device released\n");1 o }; _* k- i4 P4 R1 B1 q
- return 0;* r0 z3 E3 ? s* _' M6 k% L+ Z
- }
" q! ~8 e) t- ]; Z/ p I/ |9 z - / S7 ~2 Q7 x; a6 }& `% K8 G
- //文件读函数/ Q4 j; p9 `+ v1 t6 G& h, j- {+ D9 n
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)# h- u( e2 h' F* P+ {- C! q
- {# `' o' t& z6 c. i1 q& G
- int ret = 0;8 H/ e- `+ n$ B+ x. I. X
- //定义等待队列. u- y S! Y2 {
- DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列
` X6 Y6 d4 S# U0 C) u4 n1 }) O - add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列; Y3 N) L% y4 T- e4 ?. { q
- if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
! t# Y. m- ]9 @% ~ - {
% C5 }% J9 U" p+ S5 H5 r+ i - //printk(KERN_ALERT"\nbuffer no data\n");
1 {$ C0 K- \, ?; _" Z9 Z - //如果是非阻塞方式读取,则直接跳出) T" `1 K, F" ]
- if(filp->f_flags & O_NONBLOCK)1 L) ]4 v5 J" m; h5 d
- {% _6 v3 G- X( R7 W I2 s) z t
- ret = -EAGAIN;& i2 e) I5 O. W6 T2 k) S
- goto out;1 S4 _' o& }5 O4 J3 H. k
- }
# \9 R" w9 `) `5 J - //阻塞当前进程,放弃cpu资源/ @* {: X* f1 U
- read_quest = 1;
j4 p/ w- u% i9 | - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠* G: V$ y. X+ w. C/ f3 D
- schedule();//调度其他进程运行
% B3 w) H E" c; u$ G" a2 _3 n - if(signal_pending(current))
7 Y: y* L/ p2 m2 \: ]* X! x j - {
- D+ w" y7 r. u2 ~: x - //如果是因为信号被唤醒,则返回到系统调用之前的地方% U! J% c& H2 N$ {4 X
- ret = -ERESTARTSYS;) e5 n7 O/ T7 {1 Y r7 n
- goto out;
8 h( Q' Z& U0 { - }3 o5 b+ J# r' [$ x2 p) w. p
- }
. v* F# e3 e) ~ - //将数据拷贝到用户空间( W3 E- o' ^9 ]7 q/ l8 ^7 L" n/ w( m
- ret = k_linkQueue_getData(&queue, dst);
. Y- Y( W9 ?- o( c; u - if(ret == 0)& d& r4 ~; D; @& G
- {
% B, N2 G0 c0 T9 {* H. Y q - //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
5 L3 R* I7 H E$ h, u# }$ ~# D* a - }
6 L/ s* w( [ c3 c - out:
7 y2 G% L* j# L: t: _; P; s - remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列9 u0 `% [: H3 ^ y* b6 j/ _
- set_current_state(TASK_RUNNING);//设置当前进程为运行状态
7 F- @* c$ _8 G* A1 J - return ret;* v p$ W& i/ X. {' m
- }9 b R% i1 p- z! T8 y
( E. B e Z% g# g" r0 _- ( w3 |2 [8 T0 \' l/ x" }0 F
- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)9 K1 x& ?8 H& s2 c X1 V
- {9 b; Q# Q: t6 j; x5 X+ d: q; t
- return 0;: U8 U: d) u1 i w8 q
- }
$ j' j. T+ k$ o0 i2 |$ u; }' v - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行6 h) r: C/ Y0 `* ?+ W8 n
- open()、release()、ioctl()协同调用时被调用*/! r; e% M9 {5 J% m# f4 _- C( z
- static const struct file_operations protocol_fops =. ^0 p' G, r: E5 R9 F+ X
- {- S% @* ^; f$ {* |( q
- .owner = THIS_MODULE,8 r) \) @# ^( w/ b* `0 ~& R
- .open = protocol_open," ]; u+ ~' _+ U- Y, _
- .release = protocol_release,
* W: K8 Y H: K1 }7 m) R' u - .read = protocol_read,
( I4 K, l( |9 \: t! K9 v; R2 ~ - // .write = protocol_write,$ W5 s; H+ {* W- `$ g; u1 t$ a& j3 b
- .unlocked_ioctl=protocol_ioctl,* M) S6 f$ [9 h3 P( w. Z& W9 l" b% z
- };3 N# d7 D k, [
+ x1 e) g( `/ e' N! O- /*设备驱动模块加载函数*/
8 _9 E( j$ _9 A6 K - int __init protocol_init(void)( q8 A" n. p9 T- H$ N* ~
- {
+ S+ _" ^; l4 k - int ret = 0;3 Y" K# v: m, R3 C8 |5 T2 Z
- int result = 0;/ B; Y a; o8 s t4 Z, J% k
- //申请注册设备号(动态)
; d G- @! p# E" u0 e - ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); " f; u" a4 i$ `- D; T s' r# I' i
- if(ret < 0), x$ |/ c3 Z, p+ {/ r0 l9 i9 C
- {
0 c% n) f' J* T+ \ - printk(KERN_EMERG "alloc_chrdev_region failed\n");( t! \# l+ {( U) ?& r$ p
- return 0;& H' t7 [5 R. X
- }
! Y0 ]! Z$ ~/ }9 R; \& ~) b' { - //分配cdev
- \; ^) _9 @. R# ? U7 r! x4 D - protocol_cdev = cdev_alloc();
- r/ A! i8 I3 p5 r6 X2 M - if(protocol_cdev == NULL)
( I+ M. V$ g: m. q6 d% f( u9 c - { {" k2 H) z( U! B( _
- printk(KERN_EMERG "Cannot alloc cdev\n");
, |: L7 |2 |4 E% B - return 0;1 ^4 m w% M* m- G6 z5 ~0 C( K
- }
3 H5 c a* I! S: Z( M/ K - //初始化cdev& v$ V7 e# U$ r4 ]/ K x
- cdev_init(protocol_cdev,&protocol_fops);
, j$ f7 q1 A, e3 M# H6 R+ r - protocol_cdev->owner=THIS_MODULE;% v; x5 Q1 `+ Y5 s, k- }3 {
- //注册cdev( T2 H( R& }7 k' W2 k! Z) T
- cdev_add(protocol_cdev, protocol_dev_no, 1); " U5 j4 H t" Z1 v, F2 J
- //创建一个类7 c, M4 R6 y- x! O9 O
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);5 Q3 o& |2 V- F1 q/ l1 b& g& F9 E
- //创建设备节点
; e$ @2 m# O8 @: w - device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);& ~ e. N" u. L' n, N6 ?
- # n4 h3 p* o& |1 n8 o
- + \" L8 ~) M% k# h$ V5 O
- //申请链式循环队列作为缓冲区DSP数据帧的缓冲区- B e! A& W. M8 P4 X: I" u
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区. v$ K, t! o, I
7 J! U/ f' ~1 N! I- //映射ARM的核间通讯寄存器) X+ {! Z) f, y
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);9 l1 f/ c9 N0 {0 k3 n
- R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);7 D/ T" u; C! A {5 j/ i
- //将物理地址映射到内核空间5 X d5 C7 G3 q3 E
- mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);
* U ^ ~; j2 Z1 [7 l - //共享内存初始化
! R. c+ L: n e- t2 G0 Q - SHM_ARM_Init((unsigned char *)mem_base);5 N+ `2 z0 N8 X( `
- /*申请中断*/
' b4 B: q0 P5 n L( `5 P - 3 v+ A) Z! M8 _3 q% Y$ O
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);
' }2 G9 [6 v8 J! ` o - if(result != 0)
: q& s2 z; I; O' v - {
0 }6 s1 V( R4 l* F1 n/ w& }3 t - if(result == -EINVAL)! D# `+ C! u! t+ B& L
- {
* D$ }2 s+ o8 R; p - printk(KERN_ALERT "irq request err:-EINVAL\n");
3 h- U9 g5 }8 |3 x - }% {) {6 G) q6 ]& X0 Z
- else if(result == -EBUSY)
" R F( H! E2 H) H* | - {! W Y9 L* t1 M6 n% }
- printk(KERN_ALERT "irq request err:--EBUSY\n");' f5 m: N" r9 x. u& O5 @
- }( ]7 S" U" |; a' A y8 X) S
- else
3 c+ g7 L1 K+ |: V& J" X - {! D9 N" V" v' {' m) K% b( W, A
- printk(KERN_ALERT "irq request err: unknown\n");6 u# [. z, Q8 a$ V5 w# c+ q' ]
- } Z6 e/ U" C5 d# J v t8 p
- return result;
- e+ y) L( b3 G6 l4 @' q) V a! d - }4 f, ?/ l# N# \2 Q& G i; T5 \. G
- return 0;$ H# Q- i7 U; E; A: e# @
- }; C: H: l( c# Q1 H x2 _2 Y! y8 M
- # J8 ~$ x p) c4 i1 G, `( D8 l
- /*设备驱动模块卸载函数*/
1 t0 M! o0 }, D9 V3 r2 } - void __exit protocol_exit(void)3 k& ~, \: K$ d3 J
- {# d/ }0 {2 A( b2 }) _
- /*释放中断*/! P; W/ X0 P3 N5 u# e$ {0 t
- free_irq(IRQ_DA8XX_CHIPINT0, NULL);' \) L4 T+ _( x9 {1 k* k8 p4 P
- //释放帧缓冲的内存2 B/ c$ C8 M$ `( j8 h% ?- _
- k_linkQueue_release(&queue); T8 ]* p* W0 u# f( p2 e
- //释放寄存器映射
9 J; a e* m: X5 h* S$ V/ p - iounmap(R_CHIPSIG);& [: |; p+ \2 ^5 X3 w4 c$ x9 R B
- iounmap(R_CHIPSIG_CLR);
1 _- J" T/ J7 u P) o3 } - cdev_del(protocol_cdev); //删除cdev
0 J$ }+ {7 w8 f) a) F0 J - unregister_chrdev_region(protocol_dev_no, 1); //注销设备号
" z' O% f- x, ~0 X - device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
- D6 r+ e6 Z$ ] - class_destroy(protocol_class); //销毁设备类2 ]4 ~% e& D" W {
- printk(KERN_ALERT "exit success\n");# M% X+ H& d- k" L; y9 I& `, ]
0 ~; V$ [3 R6 ]+ I* N; x- }
; h4 H0 o' F4 i: b# o: \0 r; y5 X - //驱动其他部分省略
复制代码 / c6 ^$ s2 y# B, t, t
0 r ~5 ~3 L# |
|