本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑 , b% L s1 _3 }- H* w
: a8 r* H) p( f8 \/ f, B
项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略
, b! [+ |, U6 |+ `1 _. c( k1 ^* n
* [) x8 X8 W$ U& N; O& _- //引入其他模块函数和变量7 D/ l- x. T5 w1 n: W6 x
- extern Ping_Pong_Buffer res_buff;3 y$ }3 ?- C1 t' o5 g8 t2 u
- . v6 I' \& U5 \9 c5 C4 A: f! J6 P
- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列
( a) G% c5 I4 J3 ]" m- _ - extern void k_linkQueue_release(linkQueue *queue);//释放链队列
) m" |0 u" j3 l" L5 d, ` - extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据
8 i0 K- s+ \6 g6 |1 a - extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据) L3 H, n7 r7 ^7 c- F! S0 s+ |+ M
- 5 d2 T( w# M5 q" Y
- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化
9 [* M2 C6 J4 p; } - 6 {3 [; G* l9 k1 X5 v
- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1' S3 Q$ A1 U" h( a3 V9 _% v# A
- //设置主从设备号+ P: @# y6 ?# H3 d; ?0 \
- #define PROTOCOL_MAJOR 16 T. l) X& C7 r& X
- #define PROTOCOL_MINOR 04 G! K6 r+ a8 y* t, r+ ~) y/ d
- 3 Y: ] u" X- a' i7 C/ T
- + F% @$ B; O' ]" L4 o4 I
- , o1 Q9 j6 ~6 D4 ~" y, |9 h. e
- //定义设备驱动的名字或设备节点的名字' c( F4 u. V5 F. \( o# j
- #define DEVICE_NAME "protocol_driver"' l/ J+ c# N6 o- }5 B- U( u5 ^
- : g3 u6 D# ]$ y+ G3 u& D( O$ K+ F
+ {3 p* @' I; f$ z$ Q* j- //定义全局的循环队列作为数据缓冲区
1 e, z. H+ d# T) ^' q - k_linkQueue queue;
' Y) k/ y& M8 A* d- [8 ?
* H5 y) s% o& A, A( e! W) {- //寄存器地址映射全局变量
" @% P; G; @$ ~2 {& B - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器' i$ ] g |' w/ a4 J% x( T5 A8 h8 B3 z
- unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器' l: U6 E* A% l" U6 k
$ u5 X; N3 P, K- //物理内存映射全局变量+ ` i. C" |' f# A% h
- volatile void *mem_base = NULL;" X2 ?- L5 F. ?, C# d, L
- volatile unsigned char *cur_buf_ptr = NULL;
, L# L% j) J# a: h$ K# I+ R U - volatile unsigned char *data_ready_ptr = NULL;7 q! H4 H7 ^ u" q* T
8 l3 H! d4 B$ O6 r+ S# i
6 Q) u/ [9 f9 u
4 S3 ?$ a$ S! h% w+ G( y- //定义读数据等待队列头,IO阻塞
I3 L+ W. r( O% B; d& {* @9 G - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);6 k, ?6 \7 F5 l# R6 r
) a0 ^1 ~, A4 @, Z3 J; X5 i+ l/ W- //定义原子变量
M* |7 g _- k. Z - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备' t5 w% j/ o9 N6 N
- 2 |# q: B2 t3 D( S
- ; r, |5 f' ]# O6 \" V7 \
- //定义设备类
" g9 i' u7 T* K, W8 a* Z& a - static struct class *protocol_class;
4 O$ r* Z2 S$ T5 }' E7 M- |4 E( e - struct cdev *protocol_cdev;
2 W4 l% C/ i- G! C" h3 {* A7 R - dev_t protocol_dev_no;6 o6 \/ Y( u5 h y/ ~4 \% q
- 7 n; u1 A* w3 `" O
- /*定义tasklet和声明底半部函数并关联*/1 N3 O2 g% N- _/ H" F) c: W
- void read_data_tasklet(unsigned long);
k) E- L2 @7 z* C$ C$ k - ' a, ~% i7 `; F' K$ b
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
$ e" @4 Y% n, M - //将CHIPINT0_tasklet与read_data绑定,传入参数0/ q r& G+ Z) \2 N0 {5 F
- h, i! B: w, d1 R% }# f4 k
- /*中断处理底半部, 拷贝内存*/; a: r) w) j6 q/ c k% X! u
- void read_data(unsigned long a)
' j0 e& M6 E Z i9 F; U0 X- A* { - {- U- E( F; |/ _- x
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1
6 j3 L# C7 |) [( T8 X% ^% T - {
; r+ P/ R, q* U5 t! C7 J! e0 X - read_quest = 0;/ A k" K: R/ ]& T
- wake_up_interruptible(&wait_queue_head);//唤醒读等待队列1 N1 ?5 o3 z0 y$ I1 i R i# k6 q
- }7 |; w- B7 o- i/ m# @4 f
- * z$ I0 V4 |2 T9 Q# O! g
- }
3 V p% j A' A& |; A
! I5 J( J) n) d$ A. N0 J, [- /*中断处理顶半部*/2 |: t' }( R1 k. j. m H* A$ W7 [; W
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)4 X0 I) O7 r! b9 G
- {2 Y: y; |4 \& m# d2 \; A2 v! n
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
: b9 b7 x1 _1 E, Q - volatile Buffer_Type *next_read;. m _; V2 k6 m& @- J% n0 @ E& g
- //如果DSP数据已经ready- m* j6 E. f0 r- ^. o- [
- if(*(res_buff.cur_buffer->data_ready) == 1)
# v) M; o7 p4 v4 ^" e - {
6 c+ e% p# n1 x$ a, B% k) Z) b+ l; j - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer( \% H% |& q4 h9 G. I" X
- {
- d& x4 ?( v; l - next_read = &res_buff.pong_buffer;//下一次中断读pong buffer
8 b" Y/ ~8 J9 \9 g6 D& J - //printk(KERN_ALERT"read ping\n");3 X9 T2 d! I2 X) t
- }
0 c# W: v" s8 ~ - else
0 n8 s' ^+ p- w3 O - {, U5 h4 ~7 T+ k; b& i% e
- next_read = &res_buff.ping_buffer;//下一次中断读ping buffer- e Z8 z% A" W% t4 }7 E, E
- //printk(KERN_ALERT"read pong\n");$ |6 N- r, D: y% q
- }! A/ |+ D: U& f+ H
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer7 y, ?, T/ h: |, j, ~6 m) \
- //将数据插入链队列
- f* V' ~* h6 m+ y5 } - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);
: _: _: }3 u% H( x/ d: V( J$ Y - //标识位都重置
% J( m# G# h4 R - *(res_buff.cur_buffer->data_ready) = 0;# Z" r4 s% T# @& y
- *(res_buff.cur_buffer->data_size) = 0;
2 v3 t+ ]7 N2 t- o1 ] - res_buff.cur_buffer = next_read;
2 S: c8 U" [; {0 f - }( g$ x l* a% w0 s4 D8 }
- //清楚中断标识
0 m6 t7 p3 n) a3 q. r - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status' q* |7 X2 k; ^ |! @
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部
; G# s6 I: { O2 E. E& T
9 s. R4 o) N5 A/ Z( S- : \1 `; ], j8 v& I; q5 o
- return IRQ_HANDLED;
7 e- U0 J4 O2 ^* b) h6 T
' E- c+ J. V1 m7 t7 x- }
0 Y# w/ s8 ^$ K8 z# i
; ?' W8 b( {; K2 S; Y" s- //文件打开函数
7 Y5 ~! E+ H* y1 i6 ` - static int protocol_open(struct inode *inode, struct file *file)
" E ]. ~' d* B8 q - {5 D$ T/ y: j1 e1 [0 x& p
- int result = 0;* j2 }- _! \" U4 q& A6 i1 a
- if(!atomic_dec_and_test(&dev_available)): L8 s( }1 }2 s% M) h& S
- {5 e) o$ l& r$ u3 a
- atomic_inc(&dev_available);; R. P) B2 V4 z: ~7 u, U
- return -EBUSY;//设备已经被打开6 Z8 ?3 W" R) F% R, ~ q g
- }
" Z$ Z! N$ N+ k7 _ - printk (KERN_ALERT "\nprotrol driver open\n");4 S4 U; r& V! u- `: ~$ a8 S1 s+ d
- return 0;
- ]6 b% E: R6 D w0 W3 } - }' M5 U7 r* g2 S0 G: y7 p2 ^; z
0 v9 j7 L* Z: X. E" T' c- //文件释放函数
0 W0 C' m2 l5 ~. ~& {7 ~: O8 e - static int protocol_release(struct inode *inode, struct file *filp)& g" l/ u! l2 c3 z! w4 z; C
- {- V9 I1 n# Y' V
- atomic_inc(&dev_available);//释放设备,原子变量加1
( {- t& ?: m1 ]- R# W, [9 R- ^ - printk (KERN_ALERT "device released\n");
) V$ b( S0 n- c4 G% o ? - return 0;
. u- g% i$ P# Y9 K% y - }3 R: Q$ g/ j. k6 @$ U" m8 K
! G7 \; \9 A n/ m* V- //文件读函数4 _# Z. {: `4 b2 d# O0 h
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)5 W( f/ e2 f1 }7 T6 v: o3 m$ k
- { f1 e( A8 Z6 F# b
- int ret = 0;
0 f, J% Y6 ]( `+ ]/ b5 \ - //定义等待队列
6 k- m2 y: X( v$ \# ^ - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列) N( r3 S7 {" h% f
- add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
8 j" Z% v2 x8 v& P5 T8 l6 G% Y' i - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据& ^, ^5 p$ D9 h4 l G: ~: \
- {: Y: p, j" J3 G' C4 ~
- //printk(KERN_ALERT"\nbuffer no data\n");
# D5 _. q8 j* p7 G( [+ M3 v - //如果是非阻塞方式读取,则直接跳出
/ u2 K' Q0 u$ Z* h - if(filp->f_flags & O_NONBLOCK)! ^9 A: t, K2 r g" X4 L
- {2 @1 k; A( a0 o7 [9 f" o
- ret = -EAGAIN;* `' d. u+ |) `9 n
- goto out;
' a; G% o' `9 K- ~7 _- |! N1 E3 z - }
1 Z3 Z! V' y: R' M( ]- f - //阻塞当前进程,放弃cpu资源. p. E: T& ?: j8 T
- read_quest = 1;
& o( C- g$ t# V - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠
7 ?5 _6 @9 C) O- D- n - schedule();//调度其他进程运行9 l: k6 ?4 {% E/ M, a1 i" V+ G- S
- if(signal_pending(current)); ?9 i1 I( D! q2 z- ]( q
- {
$ f7 B/ A) z3 D U% R - //如果是因为信号被唤醒,则返回到系统调用之前的地方
+ V# j) M4 q+ S$ _ - ret = -ERESTARTSYS;
( @5 v4 f; M) E/ C4 q$ T0 N - goto out;; U1 J: K9 k) T }6 S( f: j8 K' v7 W
- }
& C$ P6 t& {2 ^( B - }7 m1 a V$ u6 K4 q
- //将数据拷贝到用户空间# }6 x$ E3 B5 s8 S, f( T0 \
- ret = k_linkQueue_getData(&queue, dst);$ F& V& u& _$ L
- if(ret == 0)6 X1 A& ?( m% E3 l
- {6 c( w- A2 C/ ~$ f+ ?( I
- //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
& L6 O: Z% B# I, N( G1 f. v/ p6 q' m - }
0 l+ U' u+ H) `. \/ {9 K - out:
. j' W% p( |0 g/ p6 { - remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列4 C- M: l: Q- u3 ^9 d
- set_current_state(TASK_RUNNING);//设置当前进程为运行状态
3 ^% z: ^$ A3 U - return ret;0 r) \/ `3 I& }
- }# }3 p$ j3 S1 ?# K* Q/ R: t) C
& ~+ h! I+ t& @2 O1 `/ f- 9 F/ y2 H5 J5 w; u# ?/ H
- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)
; Z* h: i- k x- l& Y, [ - {
7 L# a( O5 } Q. a - return 0;- o2 F' K- y3 l8 C: l
- }. F0 o; z7 X0 j& @" I0 j4 F" k
- /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行
i- A) r, |! \- X# t% o T - open()、release()、ioctl()协同调用时被调用*/! W; [1 {- S0 O, T5 M7 E6 K
- static const struct file_operations protocol_fops =
3 y# a* t! Y5 p( |3 g3 g - {0 h6 Z; x# f0 e8 G* F
- .owner = THIS_MODULE,/ G5 E% N. M$ l H" I
- .open = protocol_open,. v* t8 @# h# n" ]) F- I
- .release = protocol_release,
2 @6 l+ \% F% F: J' R( H { - .read = protocol_read,7 e# p/ A! {* t0 J
- // .write = protocol_write,' H0 B/ I5 @2 m/ u; t2 O8 S* v
- .unlocked_ioctl=protocol_ioctl,
3 j9 ?, m0 w1 I% A - };" ]% A9 k9 E0 G, Q2 p
- j' {/ z* b4 V8 K
- /*设备驱动模块加载函数*/
6 o& ?1 r: \" T - int __init protocol_init(void)& ^' Q, N9 Q) _! e1 O
- {* d0 l* z- r9 |
- int ret = 0;
5 t0 q# ^6 {7 |1 ^3 T7 n+ T - int result = 0;) o+ n7 `: T: {2 f4 n2 V
- //申请注册设备号(动态) w! e, B- \# {9 q6 t4 M& S
- ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); 3 A/ \6 {+ l D3 y/ Y
- if(ret < 0)
0 A/ N; Q5 Y4 n; W - {
( b. a2 T( D9 b, `) G2 F7 r - printk(KERN_EMERG "alloc_chrdev_region failed\n");8 h$ c' w H. M/ u) b. z+ j
- return 0;
; ~3 F6 a$ W5 t- d - }0 }; z+ M- N6 J
- //分配cdev2 t0 o% l0 \5 Y l: m6 z
- protocol_cdev = cdev_alloc();' d8 h8 o" ^1 j$ N) X
- if(protocol_cdev == NULL)3 b j+ p& X4 `: A9 {. ^
- {
) B% g5 \( s/ t! g' v# V. @ - printk(KERN_EMERG "Cannot alloc cdev\n");
' p) L7 b0 t% `- v1 Y* p& ^# n - return 0;
; \% r3 z5 Q% j( o# o! C; v5 w - }) ^3 m9 L& v5 K$ s& `
- //初始化cdev
" ]- g# D# ]/ a - cdev_init(protocol_cdev,&protocol_fops);8 w( b1 `6 _0 z
- protocol_cdev->owner=THIS_MODULE;* t4 P1 i' A: h' |8 G+ E
- //注册cdev; p/ |" u7 C+ g6 w, g% M$ @' @ C
- cdev_add(protocol_cdev, protocol_dev_no, 1);
* I! {0 I6 C" a" p - //创建一个类7 H( t" k$ ?+ I5 S2 T4 c. s* u
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);
* c$ S" r' L3 @7 \1 d# p5 J' c% I1 b - //创建设备节点& Y& `7 ?) w2 h0 T2 }6 j- E
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);6 ^% J* ~' Q! f9 ]7 n. W
- * Z9 z+ C/ ~+ |7 B' M* v
-
8 z7 L; ?; @: Q+ s- m1 }3 {+ a - //申请链式循环队列作为缓冲区DSP数据帧的缓冲区0 ~ p$ _' S7 n4 D2 b& O
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区0 O8 N3 ?% {: [& B
) y8 O$ j! N+ r! ^+ s3 ~1 Q9 Y4 O- //映射ARM的核间通讯寄存器8 Z7 h+ ]; H2 y& z
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
* G& H3 Y) M# X; `) O, e3 l. N1 S - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);& [- c7 j& }! x( p9 [
- //将物理地址映射到内核空间# c4 L9 @' `5 J1 t5 ]3 J, ?9 M
- mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);6 E. W/ N1 M7 M
- //共享内存初始化* O9 W1 V. n* r. G$ l3 ]! J
- SHM_ARM_Init((unsigned char *)mem_base);4 ?# _3 P8 r5 O- D& B
- /*申请中断*/
$ a! r8 C* {% z* M - 6 S( ]. @7 U# H; d
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);' M! Q' r/ \+ s# r$ _. U, [
- if(result != 0)
+ S2 H# N: e" }6 e$ X+ { - {
' G/ C- U. Y" r8 X - if(result == -EINVAL)( p: q: C, p% Z3 b" s9 G& G
- {4 ^1 V9 Z9 A! _4 Y0 ?( e
- printk(KERN_ALERT "irq request err:-EINVAL\n");( N0 i2 w H ^1 U
- }
" L+ s1 L. }/ ?3 o* U) o0 z - else if(result == -EBUSY) q6 U& b* C2 {; m# L) g; f
- { g- Z9 k" U ^
- printk(KERN_ALERT "irq request err:--EBUSY\n");
8 z( Z- H) ]6 p* M' E' }$ X - }
. B9 |- W( C# Y - else
, L- N: h7 E! x. q - {4 i: |/ [$ F1 w/ ]: Y, T2 q' o- k
- printk(KERN_ALERT "irq request err: unknown\n");
4 [1 ?6 U* N8 ?" l7 a. N# u - }! f) y: G% O8 K @ ?
- return result;. G i4 U# P) _/ H! ~. g d
- }: t/ B9 \' b# d' T
- return 0;
! Z& a. F3 Q+ }' N - }8 z K% n X6 K* l+ f5 Q
: w* `# A" Y; S+ T# D- /*设备驱动模块卸载函数*// q% U1 h* ]; v g
- void __exit protocol_exit(void)$ I6 R5 h/ G3 q, C. G
- {" M+ a+ q' Q/ ^' t8 ]
- /*释放中断*/+ p+ s# u4 z' P+ \, `* W
- free_irq(IRQ_DA8XX_CHIPINT0, NULL);1 s. ]; v/ l7 I/ ?7 ?, e7 U& a2 ~
- //释放帧缓冲的内存% C- T% f: m% H1 P. W: I
- k_linkQueue_release(&queue);: m' @% X( v" `6 Z) }( x
- //释放寄存器映射/ Z( s% d6 {' M. x% e% M
- iounmap(R_CHIPSIG);
# e/ K; K2 w' w0 F2 Q% W: n - iounmap(R_CHIPSIG_CLR);
. F. h* o! @2 ^2 f" A - cdev_del(protocol_cdev); //删除cdev+ y+ y9 J' l* N5 z% P& D& [1 s- K. N9 O
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号
y& }5 K2 V/ O+ u - device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
' Q0 R1 Z0 T: q8 E8 c) p - class_destroy(protocol_class); //销毁设备类
! B; ^2 Y( T% t4 ^3 {, \ - printk(KERN_ALERT "exit success\n");
4 w* @3 O4 f$ t& M9 x; l - . |0 E N0 r+ t( j: ~
- }; i% e1 M7 j* v5 p% d7 ^/ d# R4 w
- //驱动其他部分省略
复制代码 + _8 {) T8 r6 V, D+ f
0 P$ l8 v) z8 ?+ U& n. b |