本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑
9 J! x q; ^) T b2 c/ L2 h3 z
0 T7 c6 ]5 `& q项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略
9 m1 Z* u& y% @& ]8 ]
: E+ x+ S; x. {5 V1 m- //引入其他模块函数和变量5 e* L0 t0 b: O& Z' T
- extern Ping_Pong_Buffer res_buff;# P# Y: C1 R: z @
. R- _* s* j7 v6 x/ t3 j- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列2 ` |/ h0 K3 X& W- q; ?
- extern void k_linkQueue_release(linkQueue *queue);//释放链队列2 f+ s6 L8 R4 U& l
- extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据
\7 c5 M" T2 E; s# u" F - extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据
4 V5 C! P* ^( L4 M$ l1 |4 K
$ `$ w/ W z! g& Q* s% b- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化
: |% O- V5 k( C9 ^
5 X& g/ K2 d7 I& ?/ |& H' k$ D3 t- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1! U7 E" h& T: b! @ C L1 ?& Y' h
- //设置主从设备号
. C: x6 `7 l7 j - #define PROTOCOL_MAJOR 1
( I/ v) k) h4 f& U B - #define PROTOCOL_MINOR 06 R5 A* ~+ K# A
- ! h0 m3 A1 [3 D S% {8 `
- 1 X) v- f, M$ ]; K7 w1 I
+ Q; k8 Y1 E6 G7 u) }- //定义设备驱动的名字或设备节点的名字0 y7 n; n- E `7 A, f
- #define DEVICE_NAME "protocol_driver". V- s2 \) O) p
- . Y8 e r1 m7 L8 p9 S: ]6 ?
. k1 x9 {+ d$ I& p' f- //定义全局的循环队列作为数据缓冲区( n' o! O5 d0 \
- k_linkQueue queue;
" y' W, A" p. d. j+ X
, z1 x5 x% Y% v( q- //寄存器地址映射全局变量 u- H. o' W& _7 W# Q" h3 Z
- unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器# N, y7 c, x8 m/ W' R+ e1 `/ S
- unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器
x* Y8 }: u; C# `8 S
3 [! t0 U+ P5 V j) s) S! h- //物理内存映射全局变量6 b0 s# {6 R/ r, I) q6 N
- volatile void *mem_base = NULL;
8 [! o5 g8 V/ ~* M* Y - volatile unsigned char *cur_buf_ptr = NULL;
$ X" F/ d* N% o. C/ v - volatile unsigned char *data_ready_ptr = NULL;1 G% d8 p- i' x$ L# a/ H! P F P
9 b) o4 T; a5 q. b1 K- / @/ R9 I6 _) q, z' k" o
- 1 a& o2 H. C* Q% T
- //定义读数据等待队列头,IO阻塞
2 t& T9 y8 z* G& j: l- G2 R7 V) F - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);
+ Y. |' y+ F( t4 u8 I4 `
0 e, n- n& F& [) W- //定义原子变量$ H4 I9 ]) j5 T
- static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备. G' W( ~3 k6 K2 a
- r! M2 B; c. S& b4 q# o b& m- ' }9 ?* A: _; }% |
- //定义设备类
1 k6 u$ o l0 H2 \! \/ E - static struct class *protocol_class;
l2 V9 Y4 G2 W. F - struct cdev *protocol_cdev; e7 H- h" f3 Y; }4 J; @
- dev_t protocol_dev_no;" Z) e3 B& A/ O4 M
) c" x7 K5 {+ X' L) l- /*定义tasklet和声明底半部函数并关联*/$ i( s. Q; Y0 J$ P
- void read_data_tasklet(unsigned long);
* K3 I- G1 R3 Z( C- \
% e, P% [2 {5 e d- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
, G9 D5 e' X% F- l+ B - //将CHIPINT0_tasklet与read_data绑定,传入参数0
* A! O v; r/ x! ]+ B' I" D- G s
1 D# u- w3 ? d5 F$ }$ m; t- /*中断处理底半部, 拷贝内存*// c& d* t5 e: E/ I
- void read_data(unsigned long a)
( p5 \4 Y9 _; O/ ~* U - {
5 Y S$ p: w3 N/ ] - if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1
5 l* D# G& Y, _4 d - {: |) q$ _$ l) v" ]+ M
- read_quest = 0;7 u; o( `2 V9 ~: o
- wake_up_interruptible(&wait_queue_head);//唤醒读等待队列! X9 p3 t3 d- f- H+ a
- }
) n+ R" Q6 z9 d* N
1 u: k. \1 Z2 w, c2 m- a- }
0 t; {+ p* r; Y5 ^/ e - 1 k/ z, n0 A$ r& D: l6 I/ y3 @
- /*中断处理顶半部*/
2 \) D# X) p: j- t( y/ R6 z - irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)
: w6 r. o) i7 z f' F) |; _ - {
4 g& i, f% R* ^; H+ l - //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样: v W, }# j. {. C @
- volatile Buffer_Type *next_read;: G- d. C6 {. `1 G/ q
- //如果DSP数据已经ready
$ @ w; r! d5 [* s, V- J7 X - if(*(res_buff.cur_buffer->data_ready) == 1)& z$ \. Y1 a2 G3 a
- {. ]2 p4 E4 D5 B3 u
- if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer
* W" p! L2 J' x: o - {+ c4 S! H$ b: n4 z9 z
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer; w2 F! v L5 R! \+ w9 P2 R3 z6 W
- //printk(KERN_ALERT"read ping\n");7 E$ B: k' ~ l: l% x, l0 C' z
- }. `" H2 |8 s U6 T6 D1 M
- else
' A2 A# x6 n& H& \3 ~ - {; V. b2 ^+ m: ]/ F/ K
- next_read = &res_buff.ping_buffer;//下一次中断读ping buffer2 M- f0 b1 j* ~; f- ^
- //printk(KERN_ALERT"read pong\n");
9 F' ~6 `9 R4 Q' h8 c' O+ i - }. y. x6 g% [# p+ n5 T
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer m" \: D4 a8 u3 [$ d
- //将数据插入链队列
/ A1 w. C9 U" U2 m4 Y - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);
- u4 H2 }1 X- P& U3 R" N - //标识位都重置
# w2 }6 P+ C B8 X( R% G) R M2 q - *(res_buff.cur_buffer->data_ready) = 0;
0 W/ I' G0 Q2 G b7 K x - *(res_buff.cur_buffer->data_size) = 0;) ^, v+ f/ C; @8 T/ A4 O
- res_buff.cur_buffer = next_read;+ G) z; {/ a/ c" A0 q3 i, |
- }
' I+ A/ b- S3 U - //清楚中断标识* l% Y, `" ]: V0 N) ?& r6 ~+ m1 [
- *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status
1 j+ I6 P: k3 O - tasklet_schedule(&CHIPINT0_tasklet);//调度底半部 2 @8 R5 H# [2 Z; I! X. g1 S
- 6 C( G- g V' A6 n' J
+ P8 l9 A% `& R3 H: [2 `7 g- return IRQ_HANDLED;- h2 c& K; e* u( |8 P4 k+ [1 @8 W E
- 3 Z# L+ N6 b! @7 n" [4 L: q$ o
- }: H# e7 j' f1 L# X
! j7 o' H6 [; e$ `) z8 N- l- //文件打开函数% {) j) ]: g0 T4 a. i# y' x
- static int protocol_open(struct inode *inode, struct file *file)
$ Q2 \$ B7 ]6 M) N: z( [& {& G - {
! \5 X7 x. p- |7 G W0 p8 k - int result = 0;
/ @# v% U+ N/ q# m4 T' i4 E* Q3 e - if(!atomic_dec_and_test(&dev_available))
7 s5 W0 n' h) H/ n - {
% n4 L* d L. Y; Z( S2 T - atomic_inc(&dev_available);2 }! t+ F! k* |$ R* y3 k
- return -EBUSY;//设备已经被打开( S2 O( {# v* P6 K# ?- y% n, v
- }. h; _/ t! p' U3 ^
- printk (KERN_ALERT "\nprotrol driver open\n");' X! F. D' V7 b; G1 v4 ]
- return 0;3 }. e7 i0 d1 e, M. h
- }; [4 W$ n8 {; d3 g
0 d' K! i/ d- `6 U2 w1 r; }% M4 w- //文件释放函数
" |" z r9 E& g! H7 W - static int protocol_release(struct inode *inode, struct file *filp)# I) Z; E$ D# [' o6 c& C# O
- {
7 X f4 L" i/ Y4 x0 C5 o4 D0 j' R4 O( Q - atomic_inc(&dev_available);//释放设备,原子变量加1
7 N. _ l3 ~1 Q8 F: L6 k r8 F - printk (KERN_ALERT "device released\n");7 L* J) c5 l7 x; [$ m" `" q
- return 0;
# L" Q! t& ]2 A; `% @- c7 a - }
! |! R9 A0 p. n
: a! S1 Y, s1 x4 d7 M) g- n# W) l- //文件读函数5 L2 ]; L! \8 m- B6 u: G" s: z( T
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)
2 z3 d% O& G8 ~' H. f2 l# |' i - {+ F' F- J8 r2 k# o' G
- int ret = 0;+ v* e: O1 K0 }6 f4 I
- //定义等待队列
7 H% z7 m3 k( }) f! V) y - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列. {: c: g! `* R5 D" y& @1 t
- add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
* R* q$ A0 X; G2 t - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
2 O$ Q- \5 I! Z8 M* ] - {* J4 Y# w0 e. Z. \1 m2 I3 T
- //printk(KERN_ALERT"\nbuffer no data\n");
( U, `- ?5 k6 {1 `2 t) }/ l - //如果是非阻塞方式读取,则直接跳出: @0 ~; Z- E. j9 `! @ g" h& B
- if(filp->f_flags & O_NONBLOCK)5 O7 j; ]: _& S: {
- {
. i9 u/ [) J; o6 } - ret = -EAGAIN;
8 x, ]- v# N: E U2 a - goto out;
& e) Y8 h [% u* h4 C' { - }1 w# I$ B+ p( n+ x4 a! ?" r
- //阻塞当前进程,放弃cpu资源
+ {$ p8 s" H" e$ ]3 {- o/ A - read_quest = 1;
+ F& Z0 V$ [, x& m9 A, ^& i; @# A - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠3 c/ m9 n# r: P% u* S
- schedule();//调度其他进程运行% b+ o$ D1 ~# Y/ \
- if(signal_pending(current)) l# H/ X8 y1 C4 ] N
- {" h1 E3 n1 m6 b8 d( e/ I
- //如果是因为信号被唤醒,则返回到系统调用之前的地方. h9 B# i' D8 m- w6 ^) H$ I
- ret = -ERESTARTSYS;
8 t9 n+ `2 Z4 p, P9 x& `& z' S& [ - goto out;
4 I9 H- a! Q* u# N/ P( w& O. b2 A, Q! F - }
1 q& [- x6 Y! n& E - }4 x# H# N. J B
- //将数据拷贝到用户空间
7 V- @2 L4 ]% G - ret = k_linkQueue_getData(&queue, dst);& n# T- G8 {9 M( R; P+ @
- if(ret == 0)
. e) l8 Y* G! Q0 G - {
4 g/ ~" E. M& Y9 f9 D, I - //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
0 H* E! } C+ u5 x- a. V - }/ M, R* U1 A% U& g1 k) J
- out:
6 A# L: d' o) ^6 ` - remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列
" _# o" F, Q) M8 \ f% c. q - set_current_state(TASK_RUNNING);//设置当前进程为运行状态
1 f) r6 Q# r; C3 Y( e, E+ h - return ret;
9 g3 O6 S, \& V! U - }1 h! C, B- W' [ R" `3 H/ J
; l- x& ~/ s4 b% L2 s- j5 b+ I3 }, q8 M3 i
- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value), T# I: P. a+ N2 ^6 U
- {. o/ V& c" @1 B5 d4 n7 x+ `
- return 0;2 A0 M4 |, g2 x$ y% E* K1 h) ^
- }- M- }4 f9 I2 R9 Y
- /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行0 {# ?8 a& E2 o
- open()、release()、ioctl()协同调用时被调用*/' K) q$ I W! @8 f# H
- static const struct file_operations protocol_fops =
- n- }3 W; k' T - {; ]) g5 h8 M/ b* H" ^& F
- .owner = THIS_MODULE,
5 e, C" ]7 x4 B% H: n - .open = protocol_open,
& M' ?5 x' h' P! `7 ]5 N0 A5 D - .release = protocol_release,4 d0 n5 k! T$ E! o% G+ ^
- .read = protocol_read,
! `% M' V9 @5 j* M& f6 @5 [" ? - // .write = protocol_write,; c0 @7 Q9 H7 V& u* P- i# k
- .unlocked_ioctl=protocol_ioctl,
) ?& A g/ o" _" U - };5 w9 |" k9 u8 x7 S% X
- 5 S+ h' _! C0 l- P6 Q5 [
- /*设备驱动模块加载函数*/
" }$ h5 S, V( j( Z0 K, O1 { - int __init protocol_init(void): e7 N8 d" k: n1 M+ T
- {
( v) t, s/ u8 \2 w5 z) j: @0 y. g0 { - int ret = 0;! \- i$ S8 P. | i. K" i& h% [# b
- int result = 0;
( p: M" X3 O; }# o - //申请注册设备号(动态)4 r3 }6 u$ S' C+ J
- ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); 3 L8 B2 x- g d+ L8 ?
- if(ret < 0)
$ m$ ]! R! G; c0 R, [5 Q& f% F7 h8 X - {% I8 K, B+ I9 Q% m
- printk(KERN_EMERG "alloc_chrdev_region failed\n");; Y9 p4 o G" z0 c
- return 0;8 A9 B5 Q9 a# P: Y
- }7 `8 {; f. V/ {& m( G4 G! J/ A2 E/ R
- //分配cdev
( F9 C1 \1 L* n1 b - protocol_cdev = cdev_alloc();* q" b. R; d( D, K* U
- if(protocol_cdev == NULL)
0 b* m+ q; v& M* J0 g7 e' z - {
1 q9 X, \" z" s! u) I - printk(KERN_EMERG "Cannot alloc cdev\n");; _. w! J A0 U
- return 0;
; { H* E/ {) J( K - }6 d# }; r1 q9 P {! m# q
- //初始化cdev
' N, X7 P8 q t( g( B0 Z& S - cdev_init(protocol_cdev,&protocol_fops);# y- E( @4 `+ l% f5 K: N3 K3 ^
- protocol_cdev->owner=THIS_MODULE;
# p/ s) Y5 q0 A% `# K: S4 m7 a - //注册cdev) x7 O% ~4 z4 t3 y
- cdev_add(protocol_cdev, protocol_dev_no, 1);
+ }& M; n( a) K3 a6 g' s$ n8 s/ t - //创建一个类
7 ^. _' ]% Q) I7 g - protocol_class = class_create(THIS_MODULE, DEVICE_NAME);
# L6 _& w" Y- b - //创建设备节点
( P$ N$ Q( s' G, f5 A" W' h- E - device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);0 R. d+ o& J' |7 n1 e# B
- ( q7 j% v: w7 b/ p6 b
- 8 U- [0 `6 j9 \/ c7 i( V* K
- //申请链式循环队列作为缓冲区DSP数据帧的缓冲区4 G1 v5 d: [2 z& S- s
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区" ~2 Q# L9 g8 ?7 t3 a: l
; g8 |; Q5 t: h2 H2 A' m) |- `- //映射ARM的核间通讯寄存器5 v5 c$ V6 f* h) |. h- _
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);6 [+ e5 y. [, A: B( M8 x( m6 C
- R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);# B# a! A) d2 R6 U& W
- //将物理地址映射到内核空间2 }: q z5 G0 G; P4 I
- mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);
0 f4 f6 E% v H" O( L# J) W3 D& f - //共享内存初始化
9 E# F4 B3 f; A1 o- } - SHM_ARM_Init((unsigned char *)mem_base);- S. A- }6 ~$ `
- /*申请中断*/8 g0 g ~" _- L7 t
- 4 A& Y" x/ Z6 m! r0 g
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);; r2 _: n0 \/ }; f, \
- if(result != 0)
& _ h9 e% U: J: n0 [ - {
9 d! O! w' Z6 N$ s3 \; F1 y6 } - if(result == -EINVAL)+ P" _: k& J9 [+ [7 w6 x
- {0 A- x! ]$ ~& @. j' O4 c
- printk(KERN_ALERT "irq request err:-EINVAL\n");: }- k6 G* R U$ I* v h7 o
- }! q: J& u# W: _- b* U( \
- else if(result == -EBUSY)) `; T8 }" T4 T% |0 S+ W7 M0 f
- {
; A) g+ V4 o- C$ ~5 E0 E - printk(KERN_ALERT "irq request err:--EBUSY\n");6 H0 j2 R* c0 [/ K3 X3 q* s
- }
: R+ p9 F! C ^& }7 Z# A5 a- n4 d - else; }- g6 L# t5 s+ @# I
- {
% Q* H! @+ b( F4 [ v - printk(KERN_ALERT "irq request err: unknown\n");8 T. ^: M# }$ y6 o( k0 G; {
- }
* c) [4 t& ]. C: ^ - return result;
2 ^/ d; z% `1 y4 [# E8 ` - }. e- W% g! V Y* N8 S$ q
- return 0;; T* \( _3 V. R* u m
- }% o0 h( M2 @+ E2 \* M
- 9 |' H0 \" q. d- L. N" ?
- /*设备驱动模块卸载函数*/# C2 Q" Y! d# b4 V5 S( j+ o0 N$ y
- void __exit protocol_exit(void)( \ P2 V' \9 T" ~+ ]3 X' w
- {
; E9 z8 R& t+ F7 b2 U# Y - /*释放中断*/. ]7 g4 D4 a, L% Q# B8 \) A/ ]
- free_irq(IRQ_DA8XX_CHIPINT0, NULL);
0 {- o) E/ x3 m8 T$ H - //释放帧缓冲的内存
! j- x/ m; J* u - k_linkQueue_release(&queue);
2 J. ]+ K& h/ a" B5 D2 Q& { - //释放寄存器映射( W/ K; B& n: a6 c8 ]
- iounmap(R_CHIPSIG);
7 b. I9 h8 _5 v; B - iounmap(R_CHIPSIG_CLR);
! C& I. i- L+ w8 \8 y - cdev_del(protocol_cdev); //删除cdev$ v) f. h* ~; E* I& e
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号* p' j. p2 S$ X& o
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
5 u8 ?& ?9 Z2 Q' R. b* V - class_destroy(protocol_class); //销毁设备类
8 K. C4 X0 v# z- @ - printk(KERN_ALERT "exit success\n");5 \$ Q- j7 _; W; n4 U4 H
9 l2 z% \3 D5 w+ m7 t, S+ o- }! T/ k4 p4 P3 I8 @( F1 S
- //驱动其他部分省略
复制代码 3 F6 l, C4 I* m" ?# `( M( W3 W
& W- t1 R; g, B: z |