本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑 ' q9 R9 k& i7 W g0 S
- Q8 N4 E9 N- I5 z
项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略
: n% T2 t4 P7 z3 Y* @ `6 @
# u( S. l7 F& k- //引入其他模块函数和变量7 o+ j9 ^+ z# d! f* y7 g. x
- extern Ping_Pong_Buffer res_buff;
: x7 S0 ^* ~9 P& p& _: }
( F8 R5 d1 o a c' t$ ^8 B6 \ T- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列+ \4 X* }. b" s- x) l
- extern void k_linkQueue_release(linkQueue *queue);//释放链队列
7 Q1 I& ]& V+ E9 F+ J* g; `4 u - extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据2 h; s, F0 Z! n6 k3 g
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据3 G; x; L, x5 L3 d
8 N( ^' x) g+ N7 m1 U- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化: c% \" U9 o+ m' O2 g
$ S1 X, B# e) p! D' e: s4 k. m- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1
" N7 s1 }2 X6 N- `1 H/ R$ Q2 y - //设置主从设备号! Z) e% Q- E* C' w
- #define PROTOCOL_MAJOR 1- e* U {5 p4 T5 m' q* W
- #define PROTOCOL_MINOR 05 g$ h( L' D. F7 R
6 g) L5 e7 L, F- - Y) J" v/ |2 h! L3 ]; E
7 m' o" }7 P" W- //定义设备驱动的名字或设备节点的名字
, Y6 R8 S4 C3 ?4 s - #define DEVICE_NAME "protocol_driver"
8 S5 v& t( m- {2 p* W - 8 D# Q Y5 b$ F6 G( W& p
- ( D9 T" ]3 L9 g
- //定义全局的循环队列作为数据缓冲区
# |# p! F1 {5 w* @& K - k_linkQueue queue;* J5 @ c0 }8 P0 U* C# {5 T
) U7 T. e' F& o, s! l0 z: r- //寄存器地址映射全局变量
6 Y, J6 P1 x$ k7 r' U - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器
2 x# H' x/ s( N - unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器7 C& _. ?. x- B# p- o
( j4 {8 D: f1 v) r- //物理内存映射全局变量
3 W* ~9 E$ W# }( | - volatile void *mem_base = NULL;
- y0 z; v" G2 v" t5 p - volatile unsigned char *cur_buf_ptr = NULL;# J- s3 ?- M0 B5 a+ u
- volatile unsigned char *data_ready_ptr = NULL;
5 Y2 _9 |. C8 E/ z7 \7 T# F, D
( j5 {: i- x1 t9 f# _/ V2 C
& ~$ o( F; \4 Z" R) }- w* S1 O* O" s! `( B! O
- //定义读数据等待队列头,IO阻塞
9 H) x* b& d# z2 @7 S+ E - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);
3 l8 t+ A9 V6 U. k* H; F - , |8 j) Z4 x, F
- //定义原子变量! K# v4 R: h: W+ p
- static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备
, i5 j% c& o2 N8 l0 X3 S2 g! u - 3 G/ j) w* v5 Y. f
; C5 H8 t0 f) y* @$ Y$ e: o- q- //定义设备类- ?* `4 p+ A3 G
- static struct class *protocol_class;( r0 L3 ?& X: w8 w' X9 G
- struct cdev *protocol_cdev;1 }, n W8 V5 H. o% @+ x. Q
- dev_t protocol_dev_no;
: ^- P; T0 z/ |+ m! ]$ u - / [; D" p2 X" E* E7 F. {7 k, y
- /*定义tasklet和声明底半部函数并关联*/9 d# z) U4 d* c ^- _; R
- void read_data_tasklet(unsigned long);) [4 F( v/ } U9 H1 x6 U
- . Q3 r3 v1 ~. p$ g0 P. j" x. c3 w+ z
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);" N1 T# H0 i# C$ D4 [) z
- //将CHIPINT0_tasklet与read_data绑定,传入参数06 I% L. J5 F1 p% Y4 {+ p$ j% B# G
- $ t+ w7 @* T( H' n0 \
- /*中断处理底半部, 拷贝内存*/
$ y" n: t9 v" w - void read_data(unsigned long a)- R0 x* o5 k% a# W; L
- {
5 t4 Y- J" ], Y/ m - if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1
& ^* |- l+ ~" O5 T - {
, G$ [1 J7 P1 ]$ U: r* e - read_quest = 0;' {* G$ g1 i4 U! D7 M0 \: w, `- A" e
- wake_up_interruptible(&wait_queue_head);//唤醒读等待队列. A& ^: @. s/ I1 e4 Y [: V+ m
- }
- M& \8 M! B0 U( s Y - $ C7 i; g# z3 ~9 Y7 ^( ~! j7 X
- }3 }8 h% }! |9 |
; J: e3 S$ i/ |9 k/ V2 x& z& O- /*中断处理顶半部*/& {! \' c1 c/ P, `# e# a; P( t
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)2 J! o" L* K- w1 Q
- {6 i+ e$ a m/ r# H2 }( d$ g
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
) n: n. A( b! b: E - volatile Buffer_Type *next_read;
7 |/ Y& T) \8 {: R0 X. @, \ - //如果DSP数据已经ready
' x/ J5 } d9 @1 }' | - if(*(res_buff.cur_buffer->data_ready) == 1); B9 K) Q8 U4 R. g
- {6 [- Q( p5 t+ h) P0 ?$ h: Y% \
- if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer3 p) I8 j1 k: B1 _
- {9 D( c+ y0 C' ~8 W7 e
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer
* d% |8 x9 z1 h7 l. u' W7 M! { - //printk(KERN_ALERT"read ping\n");2 o X7 m+ u* U
- }" X' A! x% k) e. [- d, O
- else& v! Z( A- w. M% T
- {$ w) a' ?9 K( b, n* d. g
- next_read = &res_buff.ping_buffer;//下一次中断读ping buffer
$ V& N- }0 u4 M - //printk(KERN_ALERT"read pong\n");
! A d8 |; N% v& p2 d+ G - }- h; ]+ c9 r- S$ }9 f
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer
/ B! b% Y z" e& Y# [, e/ S! B - //将数据插入链队列
/ o, d: P9 A* o& d5 [) D - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);
3 i9 V9 G, {' y0 } e - //标识位都重置
& G1 S! J% _0 D+ F - *(res_buff.cur_buffer->data_ready) = 0;
- r! m2 g- y3 \/ G - *(res_buff.cur_buffer->data_size) = 0;
) d; f. L$ F i$ A3 L- O& V* D - res_buff.cur_buffer = next_read;
; S- ?* ?. T# d3 U; m% T2 V - }
( }: p( m% ]( ]" [1 t - //清楚中断标识
x/ m" R1 W( e) | M1 j6 W - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status
e, k7 @% E; p4 \8 ^ - tasklet_schedule(&CHIPINT0_tasklet);//调度底半部 % O& D" c6 [# K' _0 v7 Z! [+ [. |
. I4 v2 d3 P; h& y
; F F- H, f' a7 b- p! L2 s: F- return IRQ_HANDLED;
% _4 o4 ` Q* p8 {+ b D3 G
# e. ]5 q. f. {" ^- m# t, D# p J- }3 t5 T/ u6 p/ Y. y/ L u( I1 d/ a
- , s. U1 l3 a- G% l7 B
- //文件打开函数
& J: M6 C I: e& | Z2 _ - static int protocol_open(struct inode *inode, struct file *file)
. y+ f# [+ z2 a3 L" v# u' { - {# n3 i L4 `9 I& w" g6 c; h+ I9 W
- int result = 0;$ I( o4 r% `: Y" M- b5 T
- if(!atomic_dec_and_test(&dev_available))
( S0 M- W- {9 y - {
0 y- j9 ]1 L4 U0 B' I {' G - atomic_inc(&dev_available);
' ], f# ~/ f& B, K6 E. x2 ] - return -EBUSY;//设备已经被打开
5 |1 F" n& n2 F3 _( I - }, J& X& P T; b$ Y6 B: X( F
- printk (KERN_ALERT "\nprotrol driver open\n");
, B& U* `) x( t( B: l$ n' a - return 0;4 N7 T2 _, T0 H0 }$ g7 R
- }) {9 x( g( i5 [4 J m, G# g
8 i# T1 E0 I) W4 k+ q& y- //文件释放函数
; i, z2 G0 E! u) A0 f* i+ }2 r - static int protocol_release(struct inode *inode, struct file *filp)
* o- \% |/ f* |8 O - {
# e& i4 x! l- u) u" f# T( v - atomic_inc(&dev_available);//释放设备,原子变量加10 B7 P% |" ^! W" n% P
- printk (KERN_ALERT "device released\n");
, L3 T- i) q) z M* S5 Z3 a - return 0;
5 u6 Q! D4 R5 d) C+ C - }% v# v' h7 J/ E8 j. O
- ( R* |4 J/ `: x2 i% l* Q
- //文件读函数' `2 p, p* f0 e8 c9 M A% a; H
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)" g4 S7 f4 d/ ]& j5 T
- {
/ B* S3 O9 X. a1 O. C - int ret = 0;
6 J% M# l. P5 ?3 Q - //定义等待队列6 [5 u! b0 S Z+ t8 f5 O. L
- DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列, a1 P* F0 U' N+ A4 p9 ~
- add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
: e3 S4 |% j2 e - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
0 T* G7 v1 R6 {: [ Q/ k - {
% c( m: q: D3 D7 Y - //printk(KERN_ALERT"\nbuffer no data\n");$ g1 W! v' \& ~3 M
- //如果是非阻塞方式读取,则直接跳出5 q4 S4 Q4 j! V( f
- if(filp->f_flags & O_NONBLOCK)
& ]' y& z6 |* h: n# V - {# ?* y; W0 v8 ]. J" j) ?1 G
- ret = -EAGAIN;
3 }- {. E" [# P0 e7 u# H - goto out;
0 k# k* E/ G7 t: N9 O! r8 k - }4 `* G4 D; u; a3 B" j+ M4 v& u
- //阻塞当前进程,放弃cpu资源
% g2 y" u2 L7 w8 S% S - read_quest = 1; X/ d' x4 s6 F" _' H
- __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠3 }8 C% I, n/ h0 P+ H& O
- schedule();//调度其他进程运行
, m. r- Y2 y) a - if(signal_pending(current))
+ |$ B& k+ o0 F/ v - {
7 F/ T% \- ~6 H+ c7 _" ^ - //如果是因为信号被唤醒,则返回到系统调用之前的地方
2 R1 _- g2 E) s% w/ u5 i' n - ret = -ERESTARTSYS;, M4 \# r& K: y0 _0 V7 q l* U/ c
- goto out;
. U7 G; o7 i2 H! l9 I' O6 q - }2 U5 ~( v7 V' N, h) d% V
- }$ O' y& m) S$ n' |$ X$ N
- //将数据拷贝到用户空间
8 B" B6 H2 i& o6 {4 B& k - ret = k_linkQueue_getData(&queue, dst);
' {& `% n: g$ W6 T - if(ret == 0)8 a; R$ |( J( d- ? |
- {4 a. o$ ]* b2 I) ^+ S: @1 M* f
- //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);' J; A. z1 F2 E2 Q2 y: l2 x
- }
) W: c+ ] i3 H2 h# @ - out:4 Y; k/ M1 O E1 H# L) ]; F
- remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列+ `2 b; k: f0 U; U7 I
- set_current_state(TASK_RUNNING);//设置当前进程为运行状态
4 ?- f, b* S4 J. v; [, P - return ret;! M; M+ K; n5 [7 v7 F8 A( O
- }0 A6 y2 u" N% ~- H5 }
# t- Y# t( s! Q2 H3 m
- g' @) f" ]- _* D! Z* [- }& |6 v8 q- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)1 J7 _" O6 {% s! }$ y8 c
- {
9 x/ `6 P1 r* S5 V9 [ - return 0;
) s& U- H9 |/ w/ w - }: _9 f1 T7 Q8 f
- /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行
1 v2 p, @/ A) u; Z( e - open()、release()、ioctl()协同调用时被调用*/, A& R+ i4 b1 e
- static const struct file_operations protocol_fops =2 o. ? o7 n4 z& R% l2 [
- {1 {8 v8 j* r2 t1 \: P" P+ Y
- .owner = THIS_MODULE,! g- |% v# Q6 ~$ G; o- y2 \$ e
- .open = protocol_open,1 O }# [! B$ b$ X
- .release = protocol_release,% A1 H! h3 z) Q; ^: q
- .read = protocol_read,
; T( m$ f' ]+ |/ h. W2 y - // .write = protocol_write,
3 C; Z. `5 j- Z1 {7 {/ v4 R% \5 p - .unlocked_ioctl=protocol_ioctl," ]$ Q# H7 N; j$ ?
- };
3 D6 z+ u1 p5 r9 ~8 } - 5 P' A0 w+ B! ~
- /*设备驱动模块加载函数*/( t. y5 C9 X8 ~
- int __init protocol_init(void)
/ |6 H! B" P; d4 |* r - {, b& ]2 w6 e6 B9 l1 W6 e
- int ret = 0;" G8 E) w* I; \
- int result = 0;
% {$ Q0 S- k3 @; K( U - //申请注册设备号(动态)3 o* R- ^" m7 u
- ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME);
: o) z2 i2 |8 ?" X8 M - if(ret < 0)
: z; z# _' R# n* V( U - {8 K- y# ]3 u a1 ~
- printk(KERN_EMERG "alloc_chrdev_region failed\n");
8 e- i' r# s6 {' u0 m3 O8 q+ e - return 0;
( D& {8 ?. \4 p9 _$ a) N5 \ - }
* N; s: @/ z1 ?" ^) e - //分配cdev! \" t% B3 T1 H# G# S+ L1 S
- protocol_cdev = cdev_alloc();5 F* D; w2 F0 B! c. D) c6 T
- if(protocol_cdev == NULL)/ A% D+ O5 K1 K* D, F1 A8 G9 S
- {6 [0 E! V- k ?; p) k" _5 Y8 S3 h
- printk(KERN_EMERG "Cannot alloc cdev\n");& i3 K3 z0 l: p+ U( S
- return 0;
) L9 G* B: {; u2 w - }
- \* U8 ^3 u% \% U; M - //初始化cdev% T& o% X5 r5 ^5 Y2 k$ F3 L. A' r
- cdev_init(protocol_cdev,&protocol_fops);1 H/ V6 D9 h. ~+ r. N1 v* r" K+ a( V
- protocol_cdev->owner=THIS_MODULE;
% u# `0 s, H( Z' y( i6 d$ g - //注册cdev
9 q# |0 ?5 z; H l& Z8 }" n/ u - cdev_add(protocol_cdev, protocol_dev_no, 1); ( u3 i2 d/ B6 i2 }* |+ u
- //创建一个类: M- C4 b/ G% K# ~
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);8 Q, I+ Y5 m* }- S( ?: R! @
- //创建设备节点; E+ y3 p' P2 _, I" r1 h
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);- k! {0 ~8 e( x3 U: N
-
. m5 @8 W2 @1 A) p7 x - ; Z" z F/ k5 M! E/ h f4 s
- //申请链式循环队列作为缓冲区DSP数据帧的缓冲区* x; J9 F, y$ P9 J i/ z
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区+ r6 [: a1 O4 p
( u4 s3 N' u- j; H- //映射ARM的核间通讯寄存器
H$ o) Y4 P# b% D - R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);8 ?" O( D! k: D m2 S/ A
- R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);; T1 B( G2 w. C Z! S& d
- //将物理地址映射到内核空间# a/ i5 f* M4 v
- mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);( {) D* U3 M4 S2 U7 W c
- //共享内存初始化
7 O. h% [7 Z% p" H0 \0 H! M - SHM_ARM_Init((unsigned char *)mem_base);+ O& e& \% \. e1 S5 Y
- /*申请中断*/) s" f4 V. T* ~2 q% B
- # `! j8 ^/ ^6 T5 o$ t; A
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);
, [/ }, i" O4 P- O9 t0 R6 e! J - if(result != 0): m9 X& {/ j# Q) W: [, J
- {
; `, k5 ~$ k/ | o: W3 R; A - if(result == -EINVAL)
2 V( P. ], ~0 ~ - {
$ U8 `. f$ n' I6 H - printk(KERN_ALERT "irq request err:-EINVAL\n");$ N# n( Q. L8 Z( u) \! v0 w
- }' w1 B" }- ?) [( I
- else if(result == -EBUSY): E0 a, g1 e9 H* E% o7 T; W
- {
0 g( p1 I2 e) o3 E" b; { - printk(KERN_ALERT "irq request err:--EBUSY\n");$ a# f9 Q* R- Z& y2 R
- }" B/ J X1 j" Q7 N0 K
- else
% h4 Q, g% ^% Q) k) u - {
; a# P' C* G9 I# j2 U9 a1 p - printk(KERN_ALERT "irq request err: unknown\n");
# {! S) x3 t+ o$ T0 [ - } @4 _8 k$ j* b9 S* d3 Q7 R
- return result;/ n8 Q* U: j# ^ T, z3 ^0 I: S
- }3 P2 g8 }+ ?, y/ l$ h
- return 0;9 [( t7 Z) n$ k' y
- }
7 S! ^) i* u* W. X. H+ N
+ l9 P, X- B a- /*设备驱动模块卸载函数*/- \. D6 \. _. q% t# D4 F& x6 W
- void __exit protocol_exit(void)
/ y/ C3 P$ M7 O k" y - {
" m8 r5 u& }) A' G" M8 ? - /*释放中断*/
8 s" n! i' z, e9 U- n - free_irq(IRQ_DA8XX_CHIPINT0, NULL);
- R) m3 l5 T& q2 K - //释放帧缓冲的内存8 h+ |9 `/ |* f8 S
- k_linkQueue_release(&queue);
# X+ N4 J/ i, y0 p& ~6 G - //释放寄存器映射
4 d2 B: p, h& Q$ {. ^- d - iounmap(R_CHIPSIG);5 {5 }! I# k1 j
- iounmap(R_CHIPSIG_CLR);# K' Z$ i4 F: a; G
- cdev_del(protocol_cdev); //删除cdev
/ N6 w# n5 F' Y4 W! B. L - unregister_chrdev_region(protocol_dev_no, 1); //注销设备号
8 c9 X! h3 I6 O: P2 _9 d - device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
L8 [4 h0 w) j0 o: v" u0 m& {9 h, k - class_destroy(protocol_class); //销毁设备类
+ X# k( E7 [6 K$ {9 h* r - printk(KERN_ALERT "exit success\n");% @, u$ |- v# g' ^9 S* K% |" e
2 B1 g- p3 v' \$ P, S- }
7 Z) S8 x- S) m- S* Q - //驱动其他部分省略
复制代码
4 s0 |( e! }! J8 `7 w% L/ n3 u5 D* T; P- c" l, ]
|