本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑
/ }+ A( m) D. h6 l
9 j# W4 N3 I o: P5 i# ^项目要求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# Q4 C9 H A% z - " o. H0 i" I W7 \- c# ~( p
- //引入其他模块函数和变量, @7 P( N- i v0 W# G- T" C2 H0 p
- extern Ping_Pong_Buffer res_buff;" E& T0 D% H8 M9 H2 t" a
2 M$ p, \8 J; J+ x* j" W" g- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列4 K. I( ?' a, ]# L
- extern void k_linkQueue_release(linkQueue *queue);//释放链队列; \- Q1 R& Y6 z& c0 S
- extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据# w. w3 v7 A8 g' [- u9 |1 k
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据) y) B4 i$ {/ l8 A4 a
& M' n' N3 S& ^- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化" i. w: h/ @% I* @
- 8 }: R \- F5 A( }0 P' S
- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置10 M/ q$ h! V/ F5 @+ g! M2 J4 O
- //设置主从设备号- a- l0 x* c8 n! f+ P
- #define PROTOCOL_MAJOR 1
* \8 v/ W4 P1 z8 @ - #define PROTOCOL_MINOR 0- o* V2 z8 h% g1 D
3 ~! S% ]# S* m: ?6 ~' s" U3 b
/ {( h$ ~) a% i1 Y- v+ Q
& @+ R; |; g2 ]2 Q# v7 Q0 F8 Q- //定义设备驱动的名字或设备节点的名字
: d6 T8 H; e1 m. l# N6 q - #define DEVICE_NAME "protocol_driver"$ Q5 u3 z- E0 V# R) L* y- y
: i8 S1 R+ l" ~. A$ y; t
- n% [+ g) ~ g2 \- //定义全局的循环队列作为数据缓冲区
+ y H+ p0 B; F3 [2 E2 d7 C. ~0 U8 B% k; i - k_linkQueue queue;" ?2 h" I2 q! M9 l, U6 q" ?8 ~
- . x/ I4 M% P, i+ D
- //寄存器地址映射全局变量6 O. C0 z+ ]" l( }1 ~9 ^, m* a
- unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器
) b* n& T0 E2 P - unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器
4 U) B9 }, k! f B' V - & { ?* M2 i w1 w# O2 v1 f$ q
- //物理内存映射全局变量, O6 F! r4 @6 ?0 S% v2 r
- volatile void *mem_base = NULL;9 T8 {0 ^3 U* c& |
- volatile unsigned char *cur_buf_ptr = NULL;9 Z! R% q, D6 a# J$ s
- volatile unsigned char *data_ready_ptr = NULL;1 A, I1 m S4 p% y& q$ Q1 h6 J$ Y$ q' U
- 4 A* i# L' Y4 q- k% J* G' d( C9 [
- 8 V" \$ Q1 }$ _% B: d9 B
- 4 _3 @+ [8 I7 G% i* ]* `$ J
- //定义读数据等待队列头,IO阻塞: z8 }7 d8 e8 y& S2 H' |/ I! G& R0 |
- DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);
) J: |5 d" u3 I! G* [# |; M
2 u7 T1 Z1 i! g' n9 [" F- //定义原子变量' X& N" T5 \2 N8 e
- static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备
- q) F1 ]- r; R$ M - # y8 n! j# \9 V2 Z" |4 ~9 Q' B
- 1 T9 S' d( b$ e) Y. a6 z5 j2 h
- //定义设备类4 C! m. n& ^' c4 X; t; h- x
- static struct class *protocol_class;
" Q1 P, z: v; Z! k4 O' j - struct cdev *protocol_cdev;
2 E2 Y: ^" H" I+ j% y, |! A6 v - dev_t protocol_dev_no;
: K+ {5 Y5 L1 a
6 Y& L- O9 Q; ] _$ @- /*定义tasklet和声明底半部函数并关联*/
( g4 t# K! b% _4 l - void read_data_tasklet(unsigned long);
, B; Y# J& Z+ x3 e - ' y. G1 X% `- _/ q2 j4 J% O( @* A0 e
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
6 A$ k1 K5 S9 r+ R6 c1 U* ]4 k - //将CHIPINT0_tasklet与read_data绑定,传入参数04 B5 o# Z4 g2 l9 r% g, C- _% U7 i
- 1 f# J2 s1 B6 v' \, {
- /*中断处理底半部, 拷贝内存*/6 q& X1 B4 R. |4 ]1 u$ V- t8 [
- void read_data(unsigned long a)
: @. J' i) S; F% W; j# y3 R( X' C - {
4 L D: H& _/ u. h - if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1( F& ]8 V) ]4 A2 [* ]
- {
2 _) H6 l6 T; }5 C' P! O - read_quest = 0;
, J" _ M% z/ U* s, F! r - wake_up_interruptible(&wait_queue_head);//唤醒读等待队列6 ~8 r5 X3 p+ {/ I/ h' @
- }
4 T. X. U0 e% a6 t! J! I - ( [( w/ T( \! B |7 @5 _! C
- }
$ T" X. R* p9 e8 y: U# |* H
) W6 D1 \& U1 _* N- /*中断处理顶半部*/
: a/ Z+ F. r, F) u+ r4 u" u3 F - irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)
4 A4 i* y( r9 k* F! M% x. D - {
4 \3 Y2 q+ T9 [2 y$ b m( p - //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样* l4 {" o. q0 ]. x$ I! Z; o
- volatile Buffer_Type *next_read;
/ {! e8 ~! e' `# M% ?" t% I; R+ I - //如果DSP数据已经ready
8 O3 K! z4 Q' p$ g; X - if(*(res_buff.cur_buffer->data_ready) == 1)
9 M5 i; e3 i- b, }7 Q5 l9 ]# t - {
) }1 ^7 ?# W1 a - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer* h3 l' p2 |! a" u0 c& A" q3 n
- {
* s8 H# {7 {1 n - next_read = &res_buff.pong_buffer;//下一次中断读pong buffer$ R0 x; l& |3 L4 S
- //printk(KERN_ALERT"read ping\n");
) @$ T5 u* L$ i. |/ S - }
- e/ B+ A$ q8 Z& m0 d - else
- C4 q. E% @! [% ] - {
1 }( N7 _; `3 s - next_read = &res_buff.ping_buffer;//下一次中断读ping buffer
' g5 }/ l8 @1 A4 P l7 { - //printk(KERN_ALERT"read pong\n");3 }) Q: j: O- E4 ?; O6 O' O
- }
0 n) R; [) p: ?2 c0 h - *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer
% m+ \1 O: d8 S+ U) `* u+ T) M) c3 {/ q - //将数据插入链队列
) c- u0 N5 j0 N+ ? - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);
+ c! P4 ]. d; v1 @1 ? - //标识位都重置
# E6 g% {2 M$ v/ g! G* d - *(res_buff.cur_buffer->data_ready) = 0;
' R2 m; r% D9 C" B- E6 r - *(res_buff.cur_buffer->data_size) = 0;
) A% @( r( I: T- k5 t | - res_buff.cur_buffer = next_read;% X) ~6 z+ M: P) N) L) O7 \
- }' I' m2 @1 J8 f# J0 E
- //清楚中断标识
8 C/ l) o% h/ t2 _& I' Q - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status: w, G; z6 h" ]% w0 N
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部
- k! A2 A2 V! l& H' L - 3 q v% o+ @' L1 O0 d. Z- g
- . S5 b2 K% S4 k4 y2 n
- return IRQ_HANDLED;) l! _" N/ G/ P( }3 q S
7 h G) [' E8 @8 P( c- }3 p3 s- m8 S+ |/ E# ]; K
1 F" M! q, V' ?4 Y4 I- //文件打开函数$ q% _9 M$ g$ S1 |# t) S- Q* n
- static int protocol_open(struct inode *inode, struct file *file)
8 m+ o( u: D* i" Y2 Z+ Z - {
. D% [, y/ M9 D9 o1 n: \3 i - int result = 0;
; M) j0 y* R N8 \9 }! P2 j - if(!atomic_dec_and_test(&dev_available))
. j. Q) h e, h8 v- u. o% v - {
+ a7 I$ R3 L' |) m; ]3 [: W# x - atomic_inc(&dev_available);
7 e# c h' c( y$ G6 @) K - return -EBUSY;//设备已经被打开1 n& _$ [9 A% d9 v* G9 O9 Q
- }2 e- [/ g; }; ~3 e: A- ]
- printk (KERN_ALERT "\nprotrol driver open\n");/ n1 m( Q, W5 x# E( ~( l- u' @; U
- return 0;6 ?% @6 N. k$ M! x
- }. Z5 K: d2 C( F
. w- M3 Q$ D) E# ~- //文件释放函数
) r$ i8 M+ j' U - static int protocol_release(struct inode *inode, struct file *filp)
, H% H- Z+ Q3 f - {5 F7 I- b' G# r6 z
- atomic_inc(&dev_available);//释放设备,原子变量加1
/ P _, o7 u3 c1 h, _! c - printk (KERN_ALERT "device released\n");
0 a' u+ M4 @2 @5 R' T: n5 T' G - return 0;+ u( f# [% [: R' B& Y7 y
- }! f! l+ x7 E E6 L0 l
- . g3 i, x* |7 c0 ?
- //文件读函数, \" x5 }" d% u- w
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)
( Z, m# c1 W& m! ` - {% V& R3 x6 t+ q" M
- int ret = 0;4 w4 h \' M/ R' U+ D
- //定义等待队列4 R9 i$ j* i7 \& k: M7 P* V
- DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列! e, H# J+ D/ p0 B
- add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
' U3 E. n0 X. U1 z! S0 j - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据/ r( C1 n3 k9 E5 s- a
- {. `' _$ h! i1 [" T& t( M6 y- i7 k
- //printk(KERN_ALERT"\nbuffer no data\n");
% L( ~6 r* K8 \4 m0 u - //如果是非阻塞方式读取,则直接跳出& [3 a1 r* y% l: n! b
- if(filp->f_flags & O_NONBLOCK): U4 G: ~8 ?9 s2 y' k' l
- {3 [" c) H5 P q$ T0 i
- ret = -EAGAIN;
4 C2 d" a& [5 i - goto out;
; H, `& A! |$ K$ z' z% g z - }
6 H* R" N* F6 E1 ] - //阻塞当前进程,放弃cpu资源
/ k) V0 V, A$ D8 [' W - read_quest = 1;
" h b% q. ^: D, S" \ - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠
0 V( z/ _" s) ^2 f2 h - schedule();//调度其他进程运行5 S, ?. e) ^7 j
- if(signal_pending(current))- L, }% T" T3 X( M/ v* j
- {
+ x* }2 t* N6 }% h7 E0 Y - //如果是因为信号被唤醒,则返回到系统调用之前的地方
! ~* d+ {8 d8 n4 f5 X! a3 ] - ret = -ERESTARTSYS;
9 V6 ]/ \" A8 a7 _0 m - goto out;$ X: \3 b$ n( F& u P5 d
- }: @- J! ?. `7 V {, R, H- S4 I
- }* e& E1 k* y8 @+ a: D
- //将数据拷贝到用户空间3 C5 H' t" W3 r: `8 x7 h+ o
- ret = k_linkQueue_getData(&queue, dst);( G" D, ^- ]! c3 E* j, u0 I
- if(ret == 0)# r' J) l7 w9 U; S2 ^0 F
- {
# ^$ @. a% u% f$ Z - //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret); J# N% e3 H5 t- Z
- }
1 }9 r# O* k2 H& d `3 J - out:
* p6 |& M+ A/ Q8 w" s - remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列
* Q: w0 u C$ j - set_current_state(TASK_RUNNING);//设置当前进程为运行状态
7 s# A/ b! J- T6 \( P9 T - return ret;
( D1 W% F+ j8 P, D; L: u - }* G; o, O& ]/ f5 V( Q8 j
- ! q6 K% C6 j$ Y1 ?
- 0 ^# @8 e5 X! `/ I8 b& n$ S \
- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)
3 @/ q7 F& f, F$ U2 f8 S8 v5 Q - {
! h5 c( P( t& K$ ?& e1 T6 z- g - return 0;
4 I% X4 F( A2 u9 d$ U- v - }3 O$ ~/ o, Y7 K# O2 ?2 ` r" V+ H
- /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行! l2 ]! }2 G4 H2 Q$ A
- open()、release()、ioctl()协同调用时被调用*/
# Z- ~. p' R0 A, L - static const struct file_operations protocol_fops =* Q9 G l$ |( {& l$ C. q
- {" L9 L7 j/ u M. G/ x \3 E. }
- .owner = THIS_MODULE,
& U7 X) i: N; ?. ^! ~* W$ o - .open = protocol_open,7 i/ [/ B. E) T7 b
- .release = protocol_release,
8 k' R* ]" D; K4 T/ o! o8 a9 c& S- k - .read = protocol_read,& H' |4 f5 ~9 C/ G+ j3 n
- // .write = protocol_write,5 C1 ], E( y, A8 v
- .unlocked_ioctl=protocol_ioctl,$ J/ p- b P0 B; S# F# m4 l
- };
7 J5 }" X$ d/ \+ T$ |4 a% c2 w
' m. }) ?. C: ? t& _! i6 N' h- /*设备驱动模块加载函数*/
( M+ @* F) t& b) ] - int __init protocol_init(void)
@9 x" b/ s3 m - {7 L3 x! ^, x( ?3 d! I" B r8 E, ?
- int ret = 0;: p ]7 Z+ x& u7 x$ K
- int result = 0;
- _* z/ L+ ^2 V) F7 D+ _+ v - //申请注册设备号(动态): Q9 u5 u" G* M0 t6 `/ c
- ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); 6 ~5 W0 |$ c( m4 E% }
- if(ret < 0)
' {) Y' m. i; D" Y0 o4 J - {
# N, l5 U6 y/ r/ K6 Q/ A - printk(KERN_EMERG "alloc_chrdev_region failed\n");
1 G( j6 B. x! I7 @8 E2 e - return 0;
* u8 m. {! S4 E3 a, J$ e3 T( D' S/ I - }$ y- v' T% z& N% g( N# y2 u
- //分配cdev5 K) o6 E9 u& P
- protocol_cdev = cdev_alloc();3 d' w0 M9 X8 J2 d- r" [) D
- if(protocol_cdev == NULL), y, H+ c% {9 A( A
- {
% J5 ^( c# L. w2 i - printk(KERN_EMERG "Cannot alloc cdev\n");
& Y# v2 R# f5 Y9 x, G! ]$ g6 P; S - return 0;( }, D: S) Q+ K
- }! R$ J4 M4 y/ E9 ]$ o* d2 {$ y
- //初始化cdev) |: U& k5 Z% {7 \
- cdev_init(protocol_cdev,&protocol_fops);
& U: z- |( m8 f - protocol_cdev->owner=THIS_MODULE;
) R- \* X8 ^7 r+ ? - //注册cdev7 E O, C0 `% k
- cdev_add(protocol_cdev, protocol_dev_no, 1);
1 f8 u+ ~( n# ~; o - //创建一个类4 l( Z% Z: i7 E$ q6 X* d. J) n; v3 T
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);
. X3 \' W& a0 I5 D+ P0 E: m7 Y. m - //创建设备节点0 w/ ~# g- `( K
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);7 k5 D8 C0 i7 `0 ?7 ]+ l" [
-
' j8 B. g4 n4 B/ E -
/ W* y; |( E7 M% T/ s+ F - //申请链式循环队列作为缓冲区DSP数据帧的缓冲区9 h, @9 B* u$ i; C
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区5 s6 S2 O" f6 P) w; ?3 V
( e. R4 P/ Y) I3 J- //映射ARM的核间通讯寄存器& a# \+ ?" l' R$ Y
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
0 g" R6 M$ W5 [, G- |0 N - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);
9 Y# [' c% i; C) v: ]6 |; g - //将物理地址映射到内核空间3 C( l7 Y, b! a5 C& m
- mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);
- Z2 X# p f& _0 Z - //共享内存初始化$ Z& w4 E7 w, K k9 [' C
- SHM_ARM_Init((unsigned char *)mem_base);
" P, Z0 b1 b5 f, X0 O - /*申请中断*/% H c% E2 j( N7 V s6 n* h$ Y
+ t% y- H8 T2 H* S- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);. G# }# ~1 D1 K+ y L( T
- if(result != 0)4 z/ D: D$ ~# j5 Q7 e
- {/ U2 q' I; E. D) E7 Y* U
- if(result == -EINVAL)7 V# N- ~' a. P8 B, |
- {
( B+ U0 g1 z. M$ x" X1 t/ H - printk(KERN_ALERT "irq request err:-EINVAL\n");
* d" k+ r6 o9 N$ @$ {7 \; z - }
* k! R3 ^: T& F; w0 o - else if(result == -EBUSY), R9 q/ C! D: l3 }7 i1 A+ q
- {+ u! y) R) U/ n* w! W1 l. j- l
- printk(KERN_ALERT "irq request err:--EBUSY\n");1 ~4 U, h; q" B9 x9 x- C6 \
- }
. ?6 C: O* |3 w5 A/ Q5 e - else
* a1 E5 m# u, U4 | - {( l, m! V0 ]# r) X3 O
- printk(KERN_ALERT "irq request err: unknown\n");
2 M) L" E, J8 g W+ C& Q F* N - }$ _- `% f: g3 s3 D
- return result;# @" K: _2 x+ X+ G4 t+ ^6 t
- }
) g+ X' j3 R% o' l - return 0;
. F1 k x) t: {- w2 K( b - }! Y0 y- `' h; v' S. Q
! U, }3 O0 J. }' Z+ }- /*设备驱动模块卸载函数*/
6 m* C' }0 S9 g0 x) U - void __exit protocol_exit(void)/ h H! K6 I8 t8 e& p4 O' S. N' c
- {
6 ~) O) _; V: J; G! Z# A1 Z4 q0 m! j - /*释放中断*/5 }6 U- ^9 t8 M: C- }; Q
- free_irq(IRQ_DA8XX_CHIPINT0, NULL);0 s1 E4 \6 b0 \6 x4 u
- //释放帧缓冲的内存6 X. r# [ u6 a% c5 l' B( p+ b
- k_linkQueue_release(&queue);/ D- H q$ }, [" G4 i
- //释放寄存器映射* ~# }' j9 s' Y: K$ I2 [; ^ F
- iounmap(R_CHIPSIG);
# s+ t4 L* D; x7 B" j: } - iounmap(R_CHIPSIG_CLR);6 L8 R8 P: K# i& L" Z2 M2 D7 _3 }
- cdev_del(protocol_cdev); //删除cdev
/ h' z' H8 k- n. O - unregister_chrdev_region(protocol_dev_no, 1); //注销设备号# |0 J9 n6 p! J4 C
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
. h1 g1 \, d0 e2 m; Z- @/ { F - class_destroy(protocol_class); //销毁设备类: d' M" W2 M& b' {' U5 ^; P
- printk(KERN_ALERT "exit success\n");, U0 z1 e& |2 V( k; D# |
- 1 H, r6 V7 X6 d
- }
3 p( O' v+ @0 L, H% K0 x - //驱动其他部分省略
复制代码 2 g5 r& D; w. N% o3 `7 O! l8 [
% Q1 X2 _' d2 z0 \ |