本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑 & C g) F3 Q+ T6 O! [
0 L6 c. ~; \4 \8 R& Q8 z) f
项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略- H2 T% t% |: k% V6 X9 i
- / e7 V1 ?/ Y1 L/ ?8 @8 l1 m$ x$ }4 C/ @
- //引入其他模块函数和变量
7 v: R, |* E. s. f5 F- } - extern Ping_Pong_Buffer res_buff;
t* t; t7 [7 |4 y - " t' ~( m9 s2 h. l0 P2 t$ A
- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列, E: X! Y5 f& v0 I1 P5 @: s
- extern void k_linkQueue_release(linkQueue *queue);//释放链队列& A9 {) s& K" J3 v1 |
- extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据% a2 L6 W+ I$ K" J
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据" r4 h. r T( w( ^' L$ V! y
& Y) A" o0 d, K: `; H a; P2 b- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化" i8 _( ?9 l% u( U" e
- 2 D0 Z' h; [ {0 B. g7 E* r# K
- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1
& N7 K- N- k, A9 ?) m @* c - //设置主从设备号4 d$ `, F; N+ g3 U# k; U
- #define PROTOCOL_MAJOR 1
$ j8 U7 R6 S+ v! o3 ^8 K7 a* A - #define PROTOCOL_MINOR 0( _9 Z2 c0 A; U+ x
- A4 b/ E- t" e2 U7 }/ k) `: H
4 I( Z4 O& m% Z- j9 O; f$ d; ~- 0 v& @/ v# X0 s9 [1 F# d8 \+ Z
- //定义设备驱动的名字或设备节点的名字% j/ _- g5 f- x# }8 [% k3 Z% Q% G' w
- #define DEVICE_NAME "protocol_driver"7 O" d7 m/ ~! [) f
5 S# t$ u0 I/ x4 v% L- + k* u% K0 T7 P( M+ S1 D4 A. O5 d/ g
- //定义全局的循环队列作为数据缓冲区
' {* H, B' t- r, } - k_linkQueue queue;
: o$ [1 Q0 t. ?( W" L h, o1 n! E
0 R# D- l7 }3 R% T. L2 |- //寄存器地址映射全局变量
6 \4 v% T4 b9 w' S' Q6 |9 [( p) k! [ f - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器
4 P8 \5 G+ y# Y* F/ f f - unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器
" h/ O/ y; y; A: \9 i1 h - ( m Y" a* f5 G8 D4 S$ z$ ], T9 H
- //物理内存映射全局变量7 F8 K A2 w. ~) f. }
- volatile void *mem_base = NULL;
! ~0 ]1 @6 J+ G7 e - volatile unsigned char *cur_buf_ptr = NULL;$ _5 {. @+ V7 ^; |( v E
- volatile unsigned char *data_ready_ptr = NULL;
3 F9 h( Z' k! N: A3 L' f
9 u& I6 a0 w: o+ t i
5 \0 p, H: H ]# O6 o
, @. e6 h; h* n I+ f. e- //定义读数据等待队列头,IO阻塞' b& x- O" e1 M% t4 `0 |4 `- e3 t
- DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);4 v# O- j# v, R& D' c- M
7 _3 o5 a5 e3 F- //定义原子变量
) ]+ ^8 F N* P T0 D/ M - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备5 Q1 Z3 @( z1 k) p
- ' ~1 i1 r) M! O* b/ b# l6 o
- / x) i e5 Q" F8 l0 e! _
- //定义设备类
0 S' C( B0 C! F: ^! h4 } - static struct class *protocol_class;
$ ? n+ `8 s, f; f+ o+ P- [6 x - struct cdev *protocol_cdev;$ @9 U L9 V) W" z" b
- dev_t protocol_dev_no;
2 y. p. V' L0 ^+ }3 {, P - / G C ^+ v6 O9 C, ^5 Q) k
- /*定义tasklet和声明底半部函数并关联*/3 C7 q) u) D8 J3 P- C9 W
- void read_data_tasklet(unsigned long);
3 z5 p* n* h4 z( u; ^" f) y
7 U0 [3 q8 p+ A6 R- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);' [/ ]) P4 O* ~/ R8 L
- //将CHIPINT0_tasklet与read_data绑定,传入参数0% S3 u* H; d) f7 r
- & n. P, T& W4 d; i2 l* _
- /*中断处理底半部, 拷贝内存*/- O. s1 X: n5 R O% r
- void read_data(unsigned long a)
- |1 U5 r8 u2 ~5 E+ S/ d6 s - {; V% s3 Q7 |+ ]+ v% ^
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1& i/ ?/ S! p4 [' `3 _" S9 L
- {3 z" T. v( d1 [& n
- read_quest = 0;2 r, z4 X' S c) y# I$ J) m
- wake_up_interruptible(&wait_queue_head);//唤醒读等待队列* S' w9 A& S, D7 N) x& ~' j: t& Y. y
- }% o& l' ]2 ~! i7 B: k9 S2 g
- + s1 H2 [' u. t, D0 I
- }$ y9 p. G4 H- m, g5 D3 F# a6 z. ^
/ v; C$ M: C8 H N7 R- /*中断处理顶半部*/: ]* [) k) l0 s9 T+ F G
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)2 |- A/ @4 v1 W% T9 C& g" X3 T
- {, o9 r, ]* {9 }, ~/ Y
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
% Y/ G3 r- B& S0 x/ O& |" } - volatile Buffer_Type *next_read;8 O- R, r; z: J! |
- //如果DSP数据已经ready
1 P. ?! \* ]! Q% ^5 i1 v5 l& P - if(*(res_buff.cur_buffer->data_ready) == 1)
% d: K6 z% q( n" y. q& L - {
! V5 f" U( f: K) K - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer# d) `, k9 N/ h. ~9 T5 @9 E
- {
, u& `+ h( O3 g! M - next_read = &res_buff.pong_buffer;//下一次中断读pong buffer0 E' k$ r8 @' ?6 w& k& ]; ?
- //printk(KERN_ALERT"read ping\n");0 M6 a- }2 R5 O4 F8 T7 L7 C5 J
- }- N; v7 R% h* u$ V; W! r- R. Q8 Z
- else- ? t/ A {9 A7 s
- {
$ ^6 c4 Y% H" L0 F+ U6 R* v8 } - next_read = &res_buff.ping_buffer;//下一次中断读ping buffer
1 r7 X s" C0 F' _+ }+ S - //printk(KERN_ALERT"read pong\n");) ~, X7 c' w# r/ A1 ~6 |
- }
" d" B0 e5 m( E) f9 e2 `: a. A- X5 c! T - *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer
4 n; B' t/ v' B* _$ ? - //将数据插入链队列
0 m; @: g$ c8 B Q - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);
( h. t$ ?9 S; F' O" q1 y - //标识位都重置5 [9 h5 H8 E$ ]4 y& v/ |
- *(res_buff.cur_buffer->data_ready) = 0;
2 M; s& f8 v. ] - *(res_buff.cur_buffer->data_size) = 0;2 `9 d: Y+ t5 Z# ?( I8 c
- res_buff.cur_buffer = next_read;# P) `" V7 R0 X) M% f; l* h
- }
8 d# K3 R/ d1 s: v" U; B% P& o3 J" a - //清楚中断标识- C! z# a0 K# [. S+ s; B
- *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status
3 r- T5 n2 g8 R) d; y9 o n - tasklet_schedule(&CHIPINT0_tasklet);//调度底半部
; H3 c; n% s0 Z5 p" s
3 q9 Z N- m I& R/ G! p0 U- 0 D* Y. Q# k" d6 `
- return IRQ_HANDLED; I1 f" D. |. Y9 I$ a
- 1 C. z' t: z' }! t5 L
- }7 Y& t) l- N9 O Z
- 4 O( @1 c3 \& ]7 B2 z% i
- //文件打开函数
, }+ T& u9 R# d5 o - static int protocol_open(struct inode *inode, struct file *file)! L5 A/ e/ |" q9 @* H) B( I, A
- {$ Q. E6 B) _- ?+ O
- int result = 0;2 |1 y' p0 K$ _$ q5 z1 l5 ^
- if(!atomic_dec_and_test(&dev_available)); l% u) k3 e) {4 A
- {8 J" ^2 {: g8 F1 v* y2 R% Q
- atomic_inc(&dev_available);
+ Z/ E# A% ^# ~3 j+ t - return -EBUSY;//设备已经被打开; p( p; b# f7 ^, O& v- O! T' u: S8 Z& r
- }4 _# F g! Q7 H
- printk (KERN_ALERT "\nprotrol driver open\n");, f; F1 q% q- Z" J0 z
- return 0;+ I& H* W9 X) _- _
- }
& M5 w" a; p _# n+ d4 E) r! m0 {2 D - ) V& K: y8 N! S: z3 J$ O x A
- //文件释放函数0 Y0 F2 @9 W- r, T, Z9 q
- static int protocol_release(struct inode *inode, struct file *filp)9 L% w8 N W. |6 l* t: U* z
- {
- b7 r2 I, T6 B/ b - atomic_inc(&dev_available);//释放设备,原子变量加1
3 p$ f1 i' K/ f, U. Q3 u - printk (KERN_ALERT "device released\n");
1 N* O9 }7 Z7 E8 t6 c - return 0;
( R& i& R9 ?- A; o' W - }7 X' `% D& F. n4 j' Q7 b: h" m& l
; @' i) z4 J$ r2 j5 j- //文件读函数+ Q9 e- M' _ \3 ]! I
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)
, `$ Z3 L0 U9 l4 m( @! ?& |6 d) X - {
: G: q. y, \/ j- y0 B- Q7 S - int ret = 0;
, d: O' ^8 C5 W$ F R9 a! U9 c - //定义等待队列& Y* P' O7 v0 k; |2 B, t0 R# z7 W
- DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列
2 X: U) \( f r5 k! _ - add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
4 Q" }' j" O) s6 a) n: f4 a% O F - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
" t# A9 K: @' C+ f5 ^ - {
# j* W9 ~+ A2 M+ f0 l- K - //printk(KERN_ALERT"\nbuffer no data\n");: L' k* c" M0 }: b) ]" b! i
- //如果是非阻塞方式读取,则直接跳出9 \( m; x3 G" }, R( }: s( t
- if(filp->f_flags & O_NONBLOCK)3 V/ ~; F5 I' c( W! j
- {6 V# C, u9 H4 M, f. e1 Q0 H H
- ret = -EAGAIN;
& N8 ?$ P7 m2 ]# n - goto out;# }6 Z0 \1 m8 ~9 N. K! Y
- }
9 I" x; O, i h" r6 l$ a - //阻塞当前进程,放弃cpu资源
& h2 V7 N C# K# Q - read_quest = 1;
# c/ E! n, I7 T9 \) c, h - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠
7 Q5 N# T1 [& U - schedule();//调度其他进程运行
# W* G; |) \! k+ ` - if(signal_pending(current))
* ]8 r' N; a; J, W7 N2 m5 y/ E7 m - {
" ^/ }# `' T! h8 q+ B* G - //如果是因为信号被唤醒,则返回到系统调用之前的地方8 ^: W& z ? E2 A6 N2 |, O' \
- ret = -ERESTARTSYS;- K: c! ^; W8 }2 k! C# h$ j
- goto out;* G* Q# Q7 Q- B+ Z' H0 ], m
- }( t4 @# ^( ] ~" ?. |8 I
- }& i* | M& z5 J1 I' R8 Z1 o
- //将数据拷贝到用户空间
8 r/ [& X2 {' E6 W - ret = k_linkQueue_getData(&queue, dst);
! q5 H! F" q7 R7 d$ I& |3 G - if(ret == 0); E) C/ h, @5 |. |
- {
|( ?# P% s/ N9 N/ s - //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
n0 I; }# K0 ] - }/ w) A% R' ^4 [" {, }5 W# ?: |1 H
- out:$ B2 H# L4 Q8 b( B0 w. }
- remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列
, \/ L# V; ]' P; h# a$ K7 P - set_current_state(TASK_RUNNING);//设置当前进程为运行状态
# a0 X: Y# ?5 p - return ret;
) D6 ^' ]1 v2 @& Y& |3 n - }* Z) `6 y' {% P6 E- C2 r6 b# n. {
! t, S: g' G- d3 [# e% U- ( b: S2 r1 M* R1 @$ `, y, u
- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)
{) I C+ J ?4 o! ^9 [5 m, ] - {
' U7 d! o3 ?' M* p0 m$ |: n0 k7 U' z - return 0;, T8 ~- I f. k6 [) {+ _# n) P0 Y
- }: N. @1 u! p( o. P* K
- /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行
8 |+ m2 o9 _' ~ B - open()、release()、ioctl()协同调用时被调用*/# p1 b, u( `& g0 @, v! W
- static const struct file_operations protocol_fops =" y! R. r( n) ?: @ w
- {) W5 ^# j- G1 S: l1 E, L
- .owner = THIS_MODULE,1 k* U4 E8 R N( q+ X
- .open = protocol_open, K" o1 P# G1 F) b7 j& z
- .release = protocol_release,- j9 @* z& J2 \2 [( ^
- .read = protocol_read,, K; U6 K9 D4 `# f- [* k# b
- // .write = protocol_write,
+ r3 z( Z: [8 Q! v( g$ { - .unlocked_ioctl=protocol_ioctl,
3 p5 x; h! y( y5 F- J; M0 C8 ` - };7 b2 Y ^: p& e; k+ R9 R I3 w
- 9 _( d1 S/ X/ ]- N. }
- /*设备驱动模块加载函数*/
9 f% a% q1 Y! F1 c1 Y - int __init protocol_init(void)& `' }$ P) O( h5 T. _
- {
/ K% A7 n9 F9 q1 b* t$ V) C - int ret = 0;" {5 k& v1 k3 I7 m: u
- int result = 0;8 F2 y& A* |$ f! _1 U+ L
- //申请注册设备号(动态)
4 z3 a) u; ~; f1 ^9 S/ N1 ]0 M" D - ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME);
! \: r2 z5 J& m9 r% L8 ` - if(ret < 0)
; c1 }7 Z& ~3 w) p" d - {
D* i5 [# J# O2 V3 L - printk(KERN_EMERG "alloc_chrdev_region failed\n");
5 W/ ~' i+ H0 N, v - return 0;
; o9 V" F! N# ?! } - }
* |, l0 s3 Y& J2 @# K - //分配cdev
- f ^( Y, T, e5 | - protocol_cdev = cdev_alloc();
0 `; l. {4 E1 ^7 ]9 s - if(protocol_cdev == NULL), G# v" G. s9 ~5 d3 }
- {$ F* }" k" v* e% m
- printk(KERN_EMERG "Cannot alloc cdev\n");
4 |) f& r& n+ [. N% r - return 0;. P. l* L) u- c; ^2 C9 E2 `
- }
6 ?2 |# ]* n2 j2 B7 h; T( X/ x - //初始化cdev1 S& s; ]$ M: x: p9 G
- cdev_init(protocol_cdev,&protocol_fops);
4 I& Z# J ^( N - protocol_cdev->owner=THIS_MODULE;
F' I% I3 F( i' h - //注册cdev; w8 u p1 p/ l" u. s
- cdev_add(protocol_cdev, protocol_dev_no, 1);
- P+ A3 P X/ d; i - //创建一个类
) X' }4 u5 T5 X0 [/ \/ w7 J4 b7 g - protocol_class = class_create(THIS_MODULE, DEVICE_NAME);4 ?) K5 V# o+ K
- //创建设备节点
7 w" y" o# T- @. [( L9 o; J - device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);
" G1 }9 n1 X/ h3 _3 K( L/ q - * T* i, O9 Y2 G: d. n
-
( t( S. P9 I6 _+ t/ V& M0 Q6 n - //申请链式循环队列作为缓冲区DSP数据帧的缓冲区
' W' i. B- Q q" j" S4 U - k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区
+ W7 A7 L: r* K' T8 A* f3 Z' s
% i6 h: \6 \6 ?$ t- //映射ARM的核间通讯寄存器
( s7 S; ?0 B- R" ~. X" R: M# U - R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);. n1 G6 O" [5 F& u: C. p" s& l
- R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);6 {$ [! z/ { h$ s- |
- //将物理地址映射到内核空间
& Z) a0 m; Z8 Y4 P7 A1 N. b - mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);2 \* h0 m, g4 W7 A$ i- R- J
- //共享内存初始化
0 N+ s! X1 K1 V9 K+ Q - SHM_ARM_Init((unsigned char *)mem_base);
g+ m( f7 m: o9 I7 s - /*申请中断*/* x5 O. Y* B7 a
- J; @8 Z# T7 Y% g9 R% {6 b, b+ R: Z
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);0 n2 q% U3 j/ ~4 w
- if(result != 0)" Y. a* W+ M+ D- i8 h. J6 @
- {
; y. I9 `( ?; M; p3 R - if(result == -EINVAL)
# \" R( z' S4 X: Z9 X! R+ a - {6 c/ b ?. ]: ~) E+ Q' {& z I
- printk(KERN_ALERT "irq request err:-EINVAL\n");* L2 }+ h" h. J( _1 t$ e3 P. s/ a
- }" ~5 R/ \ j2 i8 L; U# K
- else if(result == -EBUSY)
. b0 {6 f8 X6 e1 ~2 y. Y - {/ t; f& L6 O% U- X, Z6 O. ~9 E
- printk(KERN_ALERT "irq request err:--EBUSY\n");
2 n; d' x8 b: z* P - }
+ Z5 f! Q) N8 _ - else$ _% P& G7 N$ ]2 q
- {0 Z! X0 W) r7 e; Q: j( m$ V
- printk(KERN_ALERT "irq request err: unknown\n");
: X, f' C# b9 g* F- f9 f - }
# s( q$ l; c* M; D- R - return result;
) y9 h# Z) {7 @/ g - }4 b0 ^, f# r$ p9 c" w! B
- return 0;( K( W8 \( s6 {% P7 ~' A5 P9 Y
- }
+ ?* Y! z" ?: D4 I - , k3 [! W9 k4 A: P" a% O5 }
- /*设备驱动模块卸载函数*/
7 m4 c, e% V8 P! o2 ~/ }! d# e! F1 m - void __exit protocol_exit(void)
. z! s" g7 H9 _& F- J6 h - {# V5 _. D3 s8 e% o
- /*释放中断*/
5 T/ F' L s# p/ b1 U - free_irq(IRQ_DA8XX_CHIPINT0, NULL);6 |% C+ ^+ Y' e0 v# ^1 C% u) ]
- //释放帧缓冲的内存
! t& I2 M5 U( R* P- V - k_linkQueue_release(&queue);
8 y6 N- c" h& P1 J( _2 j7 J& @ - //释放寄存器映射7 t: S$ _- o" P; Y& Z4 J) a
- iounmap(R_CHIPSIG);* {. S1 _8 n$ l7 ~. w& W0 l- Z
- iounmap(R_CHIPSIG_CLR);
$ p/ `$ R0 Z b& {- i m! p. t: e - cdev_del(protocol_cdev); //删除cdev# }* ]# F! r6 b; T$ t
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号
, m( _% _8 T, z5 C7 z - device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
, [ \& _, J* I: U) ^! ]; ]. o - class_destroy(protocol_class); //销毁设备类
# O N) I/ D4 S% Z - printk(KERN_ALERT "exit success\n");1 z9 [! P% V" N2 P5 C
- 5 j5 u/ f1 |: o. ]: @0 a. _8 I; H9 P) l
- }' X A- f9 q; |! g7 w7 \3 K) V
- //驱动其他部分省略
复制代码
4 E# Q* _' _; J
- o$ b) X3 J. U8 Z |