本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑 $ e4 T5 G' q9 g7 m
, m; Z( H4 E0 f/ v项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略! Z% C+ x; o% Y& F) t
- . ~2 n$ F7 S7 Q( |, n/ |9 B
- //引入其他模块函数和变量% t4 Q5 ^ Y8 U) F: t+ ]
- extern Ping_Pong_Buffer res_buff;5 R2 N! V$ h: ?$ K
- / h8 L9 f5 n9 J
- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列 E& e. L& j+ i; P2 ^% d* R
- extern void k_linkQueue_release(linkQueue *queue);//释放链队列
$ M3 D1 j& x: m/ E r6 F( q - extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据# D+ p- l+ F5 c* k' I
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据, E* ^- [1 [, h5 _. C8 C
1 a' E7 x' ?/ i4 q- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化
0 U* C3 l" n9 V: v8 D& w, K
1 t" y" z- m7 |) {1 i* F4 X+ P0 u3 @- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1
" W6 I8 T/ B! d5 E/ n2 e5 Q2 v - //设置主从设备号
1 p: U& o/ r: D' X- v - #define PROTOCOL_MAJOR 1
6 [' O. p ?/ s3 A! U, O - #define PROTOCOL_MINOR 0- E! {& y _% [- m5 k
) [5 x( N0 r8 J2 L' ?- 3 W1 j% h. _& m' M1 D3 i( |
; a' _( U0 [! f( y; w) n8 p- //定义设备驱动的名字或设备节点的名字
6 `* t! A) U5 |- K- O' C. g* x - #define DEVICE_NAME "protocol_driver"8 d5 o: b# ^; J% \# B
3 F7 i. o3 \2 Y5 @( U/ C- ]" U4 J0 g3 C' _: ~& g0 ?. i# X
- //定义全局的循环队列作为数据缓冲区! ?% D5 c3 y3 I' T( B% v* g7 g5 C1 c
- k_linkQueue queue;& H) Q8 u! v7 S+ C% y0 B
- 8 }& b( f" L( p' Y7 f
- //寄存器地址映射全局变量
! K6 X" m) x8 t9 a1 \3 M2 S: I - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器: H o6 U, s" ^' A( Y e+ Z+ X! {
- unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器
% O! U$ A5 e7 z' [# T1 ?% { X
: F( A" t8 Y, O1 E4 |" x- //物理内存映射全局变量
8 ^' D5 d4 M' d. ^7 y8 S! J, w - volatile void *mem_base = NULL;
( Y, L* z K4 P - volatile unsigned char *cur_buf_ptr = NULL;6 o0 T2 \. \ s: G! |
- volatile unsigned char *data_ready_ptr = NULL; F/ e9 F* U) {5 I, C* o
- + L2 k8 R+ r: g4 T- e% ^# b g+ M8 X
: w. y% F5 p+ h& c
6 W# Y7 ]% z7 Y- `( x: ^& z: R- //定义读数据等待队列头,IO阻塞! r9 h1 |" K) q: [6 s" l
- DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);6 j. G* R& `! w1 T7 h/ v; [) E$ B
7 X! f) j- Z- Q0 n+ P- //定义原子变量. N: j- u j& ~3 S) W P+ Q
- static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备' T" H5 X$ P7 ]: H
- # u% W$ Q- o l
# [ P6 n4 l! ?4 \- //定义设备类
& V4 r0 v2 E2 V1 `9 c3 n - static struct class *protocol_class;
* M% a' k% r9 b- i; A: p) {/ O - struct cdev *protocol_cdev;/ ~3 e) ~5 ?/ [' ]. w
- dev_t protocol_dev_no;% F3 h- b* @7 u" I4 G0 |% k
- T4 [: F; K- Q- c( I' ^; `9 s. M
- /*定义tasklet和声明底半部函数并关联*// z1 y9 R2 E, }9 @, C2 w
- void read_data_tasklet(unsigned long);
/ U, o$ }8 B3 J. m2 }+ D - * F, A: c0 A" L) F# k+ T9 P# e
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
^+ k- S+ F: b8 [5 N6 ^ - //将CHIPINT0_tasklet与read_data绑定,传入参数0& S+ e( M4 r }! x
- 1 |$ |- ~. c3 H) ^" f0 O" V
- /*中断处理底半部, 拷贝内存*/7 |( ?- ?/ U7 `! O% d& e/ m
- void read_data(unsigned long a)
) m [6 @3 r; m$ J - {% E- M- A9 }8 @) ^6 E
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1, n/ o. N4 d7 M6 D* t: w. A [8 L
- {+ L3 }' W! v( v0 f6 O: T+ j
- read_quest = 0;5 s1 r! O3 {' m( v/ H/ V" \
- wake_up_interruptible(&wait_queue_head);//唤醒读等待队列4 R& F# r: t5 D+ ^
- }5 n0 j+ t/ R1 n+ }4 g4 V7 Y3 z
- $ ^; k( F/ n. D! ?5 ]. G: G
- }
0 u9 Z4 m2 k. h+ \ - + t6 I2 X r, d3 o
- /*中断处理顶半部*/, R4 Z/ }) ]4 m# v. n
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)
5 C; Q9 C- p1 {# m- L3 v* ^ - {: {+ b# S3 ]5 w" E: K+ f% {8 `4 k6 i
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样& e7 |0 M* s9 Y" u
- volatile Buffer_Type *next_read;9 ?) N- t0 }$ v- S1 n4 g% [
- //如果DSP数据已经ready
) h9 A/ N5 S. l6 e: K8 x - if(*(res_buff.cur_buffer->data_ready) == 1)4 ~0 }% z# n# Y6 g" [. ]8 Y
- {
; y/ G1 f0 O8 K0 |6 i+ p - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer
! [; S) U2 O! _( y8 m - {9 x L% [7 @ I9 i! T
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer( [: v6 k9 ^$ H
- //printk(KERN_ALERT"read ping\n");
3 E1 f3 I' h* M8 C& R2 u - }" e* w B' ]7 ~5 `7 \
- else
/ l3 d e3 S. f. b& P - {, a: l/ |, U2 i: ^
- next_read = &res_buff.ping_buffer;//下一次中断读ping buffer
, t; c a- r9 b* O }5 @- g - //printk(KERN_ALERT"read pong\n");
3 H- z* U9 ?' y# R3 P$ K2 C; m0 R - }
0 H2 M9 s1 k0 Q, @8 V8 H - *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer
7 H! W* R0 H4 t' f - //将数据插入链队列6 U* R6 @' d& g6 h' \5 u! q
- k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);* x* {5 Q' Y- I% B8 _* L9 s
- //标识位都重置
* h! G$ c( F# s( \# \+ V - *(res_buff.cur_buffer->data_ready) = 0;
* j$ Y. O* P# Z9 r5 x$ O - *(res_buff.cur_buffer->data_size) = 0;
' F" a+ q E* }* ?/ N - res_buff.cur_buffer = next_read;
: \3 c+ O1 ~; }- B$ m [1 Q8 r - }
$ W: Q) l4 ?7 r5 e - //清楚中断标识; j# L/ s* J, C
- *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status
) A9 L, K% ~7 F; l) c9 U& b$ | - tasklet_schedule(&CHIPINT0_tasklet);//调度底半部
$ v# s2 D @. i6 h E
2 P, Q( Y1 I5 F1 `6 r
9 a: q, Q' [2 d- return IRQ_HANDLED;
# ?& Y3 N: P1 G" j- p: B
7 a; D% q- e0 p( f- }: t/ w4 O$ p: D8 r
( k4 U$ \1 S( e" ]( c3 N. }- //文件打开函数
* O- I+ J: w1 O, {$ d - static int protocol_open(struct inode *inode, struct file *file)0 R4 d" Y# I9 q+ E n/ a1 g
- {
+ }# I% K3 i- }$ N - int result = 0;& `! @- e' Q2 _- n0 S: A: \; J4 i
- if(!atomic_dec_and_test(&dev_available))
4 F2 B( L$ n4 Q# U - {
% p- Q) [9 W, ^. V. y - atomic_inc(&dev_available);
5 K6 h- c. G/ L3 U' _6 I. o9 B$ v - return -EBUSY;//设备已经被打开9 w+ }8 A; L: n7 T! ?8 ?: r
- }1 N0 n+ A L; P( p: U
- printk (KERN_ALERT "\nprotrol driver open\n");9 u; v% M: q: o" y3 c' k
- return 0;
: {8 b+ D$ S3 h3 N' ~ - }2 ~0 ?7 M9 Z6 O% T3 O
- / I, m! H1 {1 D7 y; t8 d" k
- //文件释放函数
4 Q' x$ h! [% B# M - static int protocol_release(struct inode *inode, struct file *filp)0 F- m. t1 L& J Y4 Y- G3 Z: j
- {
- n3 h. C1 w) \ - atomic_inc(&dev_available);//释放设备,原子变量加1
+ }0 `( U9 D( a) C0 x+ W, X - printk (KERN_ALERT "device released\n");
% v* z0 a% U0 I* c/ | - return 0;) N1 h( l% F1 c
- }; j9 V0 U8 s4 ]. U. c+ [
- p" h5 Q# ?7 V$ P j, `2 |( Y4 z3 i- //文件读函数4 `5 d. F3 X) ~- e9 Z) u' a8 C
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)
0 |8 \3 u- Y+ [1 e: { - {# E, \8 v& Z8 ]# s7 Q2 d
- int ret = 0;
3 t" M! Q. v& z: U, w - //定义等待队列
; i+ c2 W$ j4 t4 D% O! E- C - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列0 L3 P, D0 }, h9 A7 I2 G
- add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列) W7 j1 O) T" i5 s3 T/ N
- if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
( t7 @2 K$ e- B - {7 X& b2 M+ H( P9 v/ @3 K7 N3 k
- //printk(KERN_ALERT"\nbuffer no data\n");0 M) b2 P6 s# A( o# n
- //如果是非阻塞方式读取,则直接跳出
# g3 C! h/ y% o: K( j3 [9 V) F - if(filp->f_flags & O_NONBLOCK)6 J, g) Z# h7 W0 q1 N! e
- {4 ~5 h5 S! H6 F, \
- ret = -EAGAIN;7 F. v/ c; F$ B7 d
- goto out;
/ X. z( I* D9 V5 c6 l. x. _ - }; R! C1 h- Q! d
- //阻塞当前进程,放弃cpu资源
5 }1 X- J4 }; [$ B9 |3 e7 ~ J - read_quest = 1;1 h+ }* n9 Y& e5 H9 t
- __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠
, q+ x7 Y* c; N) G) @( D" C - schedule();//调度其他进程运行7 A" j, e4 v1 M9 J8 ?$ x# z2 J- b
- if(signal_pending(current))* k8 B* T6 t9 M* N( U
- {
$ |9 |) y' _ \/ t - //如果是因为信号被唤醒,则返回到系统调用之前的地方
: r$ E1 w; s4 {$ h* j% }6 W; u( Q - ret = -ERESTARTSYS;
/ v/ U3 m7 z( D4 ~( W, Z9 ]4 i% n - goto out;; p6 C( k1 t! {* X
- }
5 C8 ~ ^7 I, Z - }
8 z4 w3 P# x c - //将数据拷贝到用户空间
+ C" J* b: q7 q/ I1 _ - ret = k_linkQueue_getData(&queue, dst);
, V5 \. ~& A- Q4 V Z - if(ret == 0)
( A1 o+ y6 X% e - {* @- L# U& v+ f: z2 y5 _5 E
- //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);9 U5 A2 D5 t- O" L1 ~$ C% b. ?
- }
, n2 N5 k" [- Z1 ` - out:' ^% l, `, T7 T/ |, E% p
- remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列
5 p# x+ t7 w, H5 ^ - set_current_state(TASK_RUNNING);//设置当前进程为运行状态$ Q9 J. F( [7 X; j$ s
- return ret;0 C3 C) m* v2 O
- }/ a% E7 `( O" l% ^! O
- 0 N* x' N; h4 L( S( G
- # z8 E9 |0 n2 F$ X" ]
- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)
% D z2 B/ Y9 f A7 R: B, ? - {
& P8 G4 k/ s# w& Q - return 0;
, l) e) W1 i5 R( s; [ - }: C' Z1 R, ^: K9 k& N0 N. a- z+ ]
- /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行+ o5 n5 T! l3 j
- open()、release()、ioctl()协同调用时被调用*/+ `1 P9 t4 Z$ ^! J8 R% j
- static const struct file_operations protocol_fops =, ?4 K& T- p8 ^/ T7 B! x# Q2 G- M
- {
8 R& p) V. x( B+ [- N4 Y - .owner = THIS_MODULE,
" h$ h7 R( \5 w% Z - .open = protocol_open,7 Z+ M$ ^2 w8 x$ K K6 ?
- .release = protocol_release,% S" l, O* I; s
- .read = protocol_read,
2 f7 s/ V8 H8 V9 d$ Y3 X d, A - // .write = protocol_write,1 U; |1 _$ W5 |0 A
- .unlocked_ioctl=protocol_ioctl,! ]9 w O! m1 K$ M# U* z
- };
9 x/ g5 c7 o" l. Z. a+ y
) t% m' \) _0 m L$ H- /*设备驱动模块加载函数*/
1 g; W) f7 K8 B: P! M2 A) g - int __init protocol_init(void)' j$ q! R% [9 T* L( O* n# b
- {
, Z3 [) L& c- I# Y1 }. E - int ret = 0;$ j/ U o- w! R: U* h4 K& b
- int result = 0;% o! S# _$ Q. |( A5 c
- //申请注册设备号(动态)2 {, `9 ]& Q$ T" r
- ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); 0 q% W2 d- t3 j* ^1 E6 j- l& V" N
- if(ret < 0)
; y' y% r$ t/ A% f6 h$ C - {
* ?. Z. y( w0 _9 f( [/ p& i - printk(KERN_EMERG "alloc_chrdev_region failed\n");
% v* W* X: q f5 A: L - return 0;6 I% A& A0 I8 t3 h, P+ C B) ?5 e
- }! E& ^$ H3 j' U( A+ Y2 e- [
- //分配cdev W5 l' u: H+ {! g
- protocol_cdev = cdev_alloc();
+ W# w& I# E: W: G* k - if(protocol_cdev == NULL)
; Y7 Q3 e9 ^, s; j i3 s9 N - {
! D0 g* @5 u8 \; v- @0 P - printk(KERN_EMERG "Cannot alloc cdev\n");
. {: x# s( c* D0 @# B3 O - return 0;
) r6 f) ]; b9 k' h' d& J - }
1 d1 m4 q* q$ o9 i4 U - //初始化cdev
! r/ T, j) B; ?4 {- u8 s5 i - cdev_init(protocol_cdev,&protocol_fops);
e# d0 h9 _- A - protocol_cdev->owner=THIS_MODULE; D6 C) G+ d2 W* [5 j
- //注册cdev. R% ~# H4 x" i- U, I% A6 T# T
- cdev_add(protocol_cdev, protocol_dev_no, 1);
5 }- T1 n0 r: Z& I% V - //创建一个类
5 g: m F, M& j - protocol_class = class_create(THIS_MODULE, DEVICE_NAME);+ {7 n# d2 b$ @: a5 N, q; s
- //创建设备节点8 }* F |) D) R8 h+ a6 c
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);
6 t3 {8 g1 s& Y+ A+ [ -
# K# p) }+ ]7 H4 q8 V6 n - 3 P: @$ h1 ` A3 _& A2 y V
- //申请链式循环队列作为缓冲区DSP数据帧的缓冲区
+ W4 T, g2 o( c' q! i: @; [) D& Z, n - k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区
' `0 u, ?$ {$ c. c" a( j4 h3 | ` - 5 y3 j+ R3 E- U) H3 E; @( v
- //映射ARM的核间通讯寄存器7 u! I; p1 ]1 B! R8 Y: R' v8 N8 E
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
" y4 ~- D" k- e/ C) b0 J; b# c - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);+ Q8 ?& \- f3 O, R* T
- //将物理地址映射到内核空间
1 b6 d j. W- z% s9 ]; v7 U - mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);5 g. i( A! j7 r/ X+ ]- x1 e, y/ t
- //共享内存初始化4 A* A2 Z! A& G m* @7 G
- SHM_ARM_Init((unsigned char *)mem_base);# o" H# m* [" r; s! E* V* b
- /*申请中断*/
- d: {+ t& Q. t* O. w9 W) U
' _8 e P6 n1 C* y. n- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);
! u7 p8 y4 V, {+ v, G9 _ - if(result != 0)
+ O. K3 Y$ `! u9 [5 R; ]8 O5 M8 ~ - {+ @- [6 ~+ C; b1 M* w' W7 c
- if(result == -EINVAL)
7 m! U/ [, Q5 M+ o4 g7 `2 W2 g - {2 |; [- i8 _/ J6 n; o) E
- printk(KERN_ALERT "irq request err:-EINVAL\n");
" T1 o/ P' e$ i! S3 x - }
7 F8 G! f z. B2 h5 H/ g7 o - else if(result == -EBUSY)
! ]( U% p6 ? p - {
a( ~' N0 \1 S( H - printk(KERN_ALERT "irq request err:--EBUSY\n");
( w& t0 y# g6 Z, y+ H - }
3 H5 `* y- `& H2 N& y- X4 G - else! k0 U3 G% Q; }* n2 W/ R. g
- {: f7 g1 Y0 A& C+ Z$ }" i# S9 @
- printk(KERN_ALERT "irq request err: unknown\n");
; j+ }2 b( e" T& u G - }7 J, k6 u% | I0 N# d+ X
- return result;/ U# j( _: E9 o `, C
- }6 P- \% s, E J$ a2 n
- return 0;
0 K3 r8 ~: D7 \- x7 r - }
& D/ L4 H" A. o6 ^* {7 k
% i* S0 \( |* R* ?; `& w- /*设备驱动模块卸载函数*/
1 M) y2 w- k# v1 b: ]( b - void __exit protocol_exit(void)" g) a7 Q8 s$ H2 D, B" _* f# y
- {
1 b3 K0 M2 G0 ~( {4 E7 O% e - /*释放中断*/* g* U# ^. P& H: q* h( ^5 f; f9 m9 s
- free_irq(IRQ_DA8XX_CHIPINT0, NULL);6 }0 e% P1 C8 u# I, B* _/ x
- //释放帧缓冲的内存
5 |7 c+ o7 H. H2 P* H& r+ o - k_linkQueue_release(&queue);
7 [9 C% E9 |& R3 Y* M+ t3 p- \ - //释放寄存器映射
: T$ C1 y8 n: O - iounmap(R_CHIPSIG);
g" {# ~& Y/ K8 L0 K: X" b - iounmap(R_CHIPSIG_CLR);
1 k; D6 K' i3 |2 H- d4 { - cdev_del(protocol_cdev); //删除cdev
; n2 `' h; Y- {+ ?/ s - unregister_chrdev_region(protocol_dev_no, 1); //注销设备号6 o& {" L5 g, P6 M! }) |8 k- Q' {
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点/ w$ N/ E" {( c! P& n5 i
- class_destroy(protocol_class); //销毁设备类
8 o4 u1 ]) R3 E, Z- i4 H6 K7 K - printk(KERN_ALERT "exit success\n");
2 _' U7 F! F: E& U2 P
. O0 |/ J$ b4 J9 v; [7 T- }2 v: G) B2 d) P
- //驱动其他部分省略
复制代码
8 [- y: R( p% C' S9 v% V( E
9 b+ B; J3 Q0 n; j- u- O |