本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑 & X; S* X6 K1 Z# e+ I3 {$ I5 u
5 y- R/ G: k# ~
项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略
~& c& r$ _1 k) @, g - 6 K. T0 @2 i. Q6 A) ^ G. q
- //引入其他模块函数和变量
6 y( h: P- x, I! z - extern Ping_Pong_Buffer res_buff;
1 I+ c) `0 `+ h2 G' q$ Y - , K4 F' R3 \7 j: I# B' ~2 M9 h
- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列2 _* v2 @& @# {9 d, k7 F
- extern void k_linkQueue_release(linkQueue *queue);//释放链队列; }, t, W& M9 M
- extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据
6 B3 k& U0 T/ q7 \+ l - extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据
8 h3 K& F t4 W - # @7 ^: y3 _ f" u! @
- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化
6 z: I* c; k$ x5 [1 Q - " |, |- x& F' O* w/ T3 c
- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1+ Z3 E+ z, l) S0 @
- //设置主从设备号
; ^- f+ Z' v! |5 e - #define PROTOCOL_MAJOR 1
; j% j' Y$ w* x, O0 R. Z - #define PROTOCOL_MINOR 0
% D* p3 g, K3 O# \, s9 x - 8 \- M; ?. `( `. U" u+ ]
- - F+ |6 H/ L9 @6 e- H7 {
- 7 H, G/ Q1 C, A) V
- //定义设备驱动的名字或设备节点的名字' O5 {! V+ M! ~/ Q- e8 O% O
- #define DEVICE_NAME "protocol_driver"& ~% F* \$ |9 {* K
x. d/ x& l' n- P- J- 9 g& Z) ~" `, C! J5 Z9 f* y& E
- //定义全局的循环队列作为数据缓冲区
_8 L* f" H" b- P' W - k_linkQueue queue;* z- s! Y! C# q; u& S8 v
- - |: C1 I" i5 \6 H% I: g1 u0 d3 x
- //寄存器地址映射全局变量- @7 l0 f1 `1 U0 s! ^5 ]+ E4 h
- unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器! N7 y. v5 ?4 ~: {" c( ^
- unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器4 F; o5 ^& q+ N' [1 C- T/ e& Q
- , F& p: Z6 ?) p2 j7 M) a
- //物理内存映射全局变量9 f2 h0 n' d' `! S; u! U& r8 X
- volatile void *mem_base = NULL;
9 k* \( u1 D" O/ i! K - volatile unsigned char *cur_buf_ptr = NULL;
# Q4 V }: p4 r' n( a - volatile unsigned char *data_ready_ptr = NULL;
3 m3 A& z' R% _; o
; k& x3 p7 N! g- 1 P9 X2 a! z) ~, i) k* z) X8 i
8 E9 q4 V1 v7 p/ A# e- //定义读数据等待队列头,IO阻塞
9 a: N# \: M3 D* G* B# y7 J - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head); N8 @, `0 s; j0 E
- 2 `7 l4 S% P) J1 o. B" C
- //定义原子变量7 X8 e s7 ]& E
- static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备! ^" M' _% I) f/ n
- ; Y) S" K% U7 ]/ @7 U* R4 z
( Y% \4 j% P. q( Y5 E, M7 g- //定义设备类
2 B8 q7 Q: d, P: z - static struct class *protocol_class;# z& M/ {5 U# v4 r, Q6 d+ H
- struct cdev *protocol_cdev;- J0 Z! K6 H# T5 j) S" @- I
- dev_t protocol_dev_no;
! I' E8 n0 _, Q8 r7 y - ' v& Z) E S4 h: ^9 u
- /*定义tasklet和声明底半部函数并关联*/
& H' o, Y6 a3 P. p- I1 i( {9 U+ ]0 U3 k - void read_data_tasklet(unsigned long);
( G1 O- r& N2 `4 A' T - $ y" g( {5 V# W" G
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);9 y4 u- J0 I" {
- //将CHIPINT0_tasklet与read_data绑定,传入参数0
$ U2 T: ]( H; g3 } H5 Z9 s
7 ?! V' H# W2 ]' {6 n1 e Y! z- /*中断处理底半部, 拷贝内存*/$ c# \+ ~: S/ V3 N! P
- void read_data(unsigned long a)
8 c4 |4 F$ r1 O- }( R" J$ A; B - {
8 M1 l z4 g, `9 W' d V - if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1/ ~+ o: |2 Q+ n+ Q/ [, E9 o9 s3 T
- {8 c0 E% k/ A- P8 o
- read_quest = 0;( }) { Y" l2 C2 O) |: V+ F# M% i
- wake_up_interruptible(&wait_queue_head);//唤醒读等待队列* P$ [, G: V$ o# O5 Z, t
- }
, t" F* L# d0 }9 u6 ~: D5 u, {( i4 C/ d% { - ' |3 n( S. M3 |1 Z# [, _
- }5 @+ J" B3 ~* @* P
/ {$ k6 n3 E+ ?, Z6 Q- /*中断处理顶半部*/
0 c8 k9 r$ a2 _& o - irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)
4 _. W ?5 _4 E5 E* Y - {7 }4 a# O( I. k- S. G5 r$ q
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
2 @6 y! M7 Y; A, o. q$ d- _ - volatile Buffer_Type *next_read;
* ^; w( B- q- p+ R" ? - //如果DSP数据已经ready1 `; C, A7 H& ~) q8 \
- if(*(res_buff.cur_buffer->data_ready) == 1)
; T X5 _' K7 { m8 T - {
1 w, c+ U* H+ R( e' v - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer$ e& {1 d6 ]# S" O
- {$ v% d* R; `( |. `
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer
: F! ] s0 M& q5 s' I! J6 Y8 ] - //printk(KERN_ALERT"read ping\n");
3 ^6 `/ B) O$ L- r6 Y3 G6 H - }5 z. k$ v+ U( Q
- else
$ U5 S. ]0 s# o) a5 n2 X& v - {0 i: s' m$ f8 o# R
- next_read = &res_buff.ping_buffer;//下一次中断读ping buffer
8 r( @+ n6 | O1 C3 v - //printk(KERN_ALERT"read pong\n");
& d# k9 Z4 l. F6 l# O - }9 G! S' d3 I# i
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer, `; ?. v/ Z6 @. L
- //将数据插入链队列$ H% J. N7 G- G F0 J% n8 t' \
- k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);
7 q( N# a) J1 s# w - //标识位都重置4 z9 Y# f: s% Y+ w5 U( A8 \/ m
- *(res_buff.cur_buffer->data_ready) = 0;5 u; K: m3 D" x; U. d
- *(res_buff.cur_buffer->data_size) = 0;+ K) P; `3 |- A, Y4 p1 Z# B4 f
- res_buff.cur_buffer = next_read;
6 M, ]% S. n1 h# e0 X( t - } F' Q+ B% t+ N9 g4 _7 d) j
- //清楚中断标识
) [* @8 B" t. [1 f; @ - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status% w& N2 S; l+ V7 {6 ^7 X2 N
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部
+ f. t8 q6 r9 u - 7 [. x/ r+ r2 G" ]5 p) O
- ) S8 H$ i# e. X
- return IRQ_HANDLED;
, O; D3 t, @# R; C# b3 }
5 O& t3 L: ^4 P) A; ~$ D- }0 f1 ]* w; r7 r( D3 E
+ H& j& \3 v* P1 J- //文件打开函数! f9 E+ M1 T1 i! {/ `' W5 }3 C, ~
- static int protocol_open(struct inode *inode, struct file *file)
0 a a3 C; F4 y/ K8 l* [ - {- M( w; X; C5 @5 ~
- int result = 0;8 s3 A: u/ s+ U+ u3 D
- if(!atomic_dec_and_test(&dev_available))' e9 w" }7 v+ |3 ^/ L+ L" X" |- D
- {9 s* N4 v8 n4 F0 g' V
- atomic_inc(&dev_available);
% S) @) w7 {; Z V1 B - return -EBUSY;//设备已经被打开1 o& x- T1 b4 a4 q- H( g
- }
8 i5 e% y$ H0 m: {( w - printk (KERN_ALERT "\nprotrol driver open\n");
' M' }3 N# H2 d4 e5 p7 Y! X( @ - return 0;& R) b# U- M2 i* h+ A7 _
- }
( h, ^; A( [1 \- |; G7 v
& s: b9 z8 Q$ L; K& ~- j- //文件释放函数/ U, p0 H8 t0 W, c% r. P
- static int protocol_release(struct inode *inode, struct file *filp)' c9 x4 R5 @7 k/ }
- {0 o: O: h9 F7 N0 [, P
- atomic_inc(&dev_available);//释放设备,原子变量加1
/ [9 J% P) b# \ I - printk (KERN_ALERT "device released\n"); N: D0 ]% R1 t
- return 0;
! e: [3 e8 k% x. d( E7 ? - }2 @8 B G1 B* X" S& E; B
- ' U% U& Y/ y$ a# y
- //文件读函数2 J( t1 ^& n4 F4 W
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)
2 v: }( X( f+ }/ i- p- H$ h" C - {9 A5 e* I/ w$ r- Q8 q. i: c+ o9 T
- int ret = 0;
7 r' B* Y* t) T' t' p - //定义等待队列4 G- g& d( x4 }" F! _; i0 J0 B( C
- DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列
# k; k( U' p) _! {4 G& F1 i - add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列' `* @+ M9 n1 z
- if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
4 }* [/ y) l5 K5 o7 u5 x$ ? - {; H8 p- Y+ i7 S# h' {' Z
- //printk(KERN_ALERT"\nbuffer no data\n");* G( H6 q8 e: f; r7 y* M# o/ G( s
- //如果是非阻塞方式读取,则直接跳出
7 y8 Y& C1 F# U6 s - if(filp->f_flags & O_NONBLOCK); x4 a7 E; k: G/ c
- {. e; w9 t! D+ [8 [9 o
- ret = -EAGAIN;8 H9 F$ Z$ O4 Q, A
- goto out;2 x7 X' i% S: e
- }
# O- X3 ]+ i( p* ^, H - //阻塞当前进程,放弃cpu资源7 R- H: M% O! g( _0 p e# O
- read_quest = 1;
( c# N: Y9 o7 \, i - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠8 s* U9 O/ c2 e! t+ E2 \4 r0 Z
- schedule();//调度其他进程运行
. r$ r$ U+ U# T. j - if(signal_pending(current))
Z0 E! l, w6 B5 v - {8 l! M/ l' G3 s: g, E3 `$ ]* u; X
- //如果是因为信号被唤醒,则返回到系统调用之前的地方% ~) z! e X0 l, q; L b
- ret = -ERESTARTSYS;) k- L4 e; v% p' i
- goto out;6 I( |' C3 y$ r& H1 n, d+ J) r# z+ X2 l* d
- }2 v6 A5 d0 V# z% G+ V
- }
' l& i& P1 m2 g/ Z; p0 \; y6 p0 s - //将数据拷贝到用户空间* A: K8 O2 `& b0 p$ M: d
- ret = k_linkQueue_getData(&queue, dst);( o9 R8 p% C) b8 N C* H J! c
- if(ret == 0)
. X$ W2 v! P4 r1 z - {# i( a& v6 T( f4 d' D
- //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
: q2 |) n. J( Q* I* y - }
8 _* o) W3 k* l! Y7 ?8 T A - out:! i* F+ {' V) l. O
- remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列
9 f' C- X n- M& f) l4 N0 A - set_current_state(TASK_RUNNING);//设置当前进程为运行状态
; A/ `7 \0 H; S1 T$ P# y) X. T - return ret;" q6 \' H; _4 H2 V! q) [+ m* t
- }
t% F) Q9 F+ v0 d% @# m% Y
" P3 a: w# v' ]6 p; A) \
2 Z, s+ i9 _2 k( ?6 v( L# c: o! e" u# [- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)
; s& t4 l" G1 G$ {- S, h; T x' ?) L - {
8 L/ ~5 F U& d6 a - return 0;
" q" U0 z2 e( W7 g6 O - }
# U' O. h1 e! u \' g0 B2 F - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行
$ ~" ]" Y m3 Y0 R' z0 k - open()、release()、ioctl()协同调用时被调用*/
* M6 P% e `8 P - static const struct file_operations protocol_fops =
- J; [! u$ E8 [0 @ - {
5 `7 y3 ?$ u! k - .owner = THIS_MODULE,
. C C' D& p. f - .open = protocol_open,
6 U$ c5 b S# B* r# ]0 i5 ~' \ - .release = protocol_release,* A G7 [/ O9 L$ Z8 {3 K1 V
- .read = protocol_read,
) e0 c+ v; i* q6 Y# I: N0 V - // .write = protocol_write," {: S9 }2 C. H" i/ ?! ?% o9 d- f1 ]8 {
- .unlocked_ioctl=protocol_ioctl,/ `- Z1 X, J4 n K3 |& P# b
- };
9 O9 a: }. L) ?: \+ i c - 7 W6 z% M) w" F+ ]9 z
- /*设备驱动模块加载函数*/( _3 D b) X; o5 @$ H
- int __init protocol_init(void)$ d* N3 a8 Q' j R% E
- {
S. {; a6 j5 Y* P - int ret = 0;
* l. P) g' u; T1 p: z, o1 B/ _ - int result = 0;3 E: j8 o) L0 M0 \* N. m
- //申请注册设备号(动态)
) p3 R1 G7 R$ i$ u# \# [* y6 z - ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); - k$ T; V8 L8 e/ M
- if(ret < 0)% x- }* s$ _/ i" c- P6 q
- {
9 S3 ^7 f" c/ o5 X: q+ }: s - printk(KERN_EMERG "alloc_chrdev_region failed\n");: }/ e, Q# D- K: Y) j3 \
- return 0;
2 D2 Z' C( m8 ?' A4 q - }
- U0 m+ m' ~: i1 c" l7 U: y - //分配cdev
% O' Y9 j9 z6 m2 z, O" h - protocol_cdev = cdev_alloc();# q# _+ W) q$ x: h' ~0 ]
- if(protocol_cdev == NULL). }" p* ^; w' h: K
- { h7 V* o) u' X4 D. G5 f# p% A
- printk(KERN_EMERG "Cannot alloc cdev\n");* B; T. u% z! y1 D3 i) v
- return 0;& p! @: V; j; h5 f
- }" a( C. o2 x2 c. k G% W! n
- //初始化cdev
$ N1 ?$ t) s2 j5 G& V - cdev_init(protocol_cdev,&protocol_fops);3 U* D& J* ?% O
- protocol_cdev->owner=THIS_MODULE;6 K( u6 w% L7 O5 a
- //注册cdev
4 P8 M* L7 y. U" ?8 o1 T6 c - cdev_add(protocol_cdev, protocol_dev_no, 1);
- {9 G- r6 T* O. _$ U# X! G& U; v - //创建一个类& c8 L# i, w1 T4 x; Q" Y
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);* T# k8 {* I. e7 k' x& C+ v
- //创建设备节点
, }* l$ b% J* T - device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);( A9 A& A/ ^& K* ]3 C2 I; y
-
6 r3 N; R2 \& ?/ X2 i -
0 Z' L, D+ X2 s+ r0 U# H - //申请链式循环队列作为缓冲区DSP数据帧的缓冲区
9 s2 o+ R) e" ~& }2 k& Z; e - k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区
% z, T! u7 F/ P8 {8 H; [' l
( v& b" E- s; ^7 n# y- //映射ARM的核间通讯寄存器& O f8 i/ u; q( o* _
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
) S* v* m6 Z V: X - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);+ m" I) K( X$ R8 P' I: B
- //将物理地址映射到内核空间* p) G$ @, d6 R6 f( S; k+ l
- mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);
" E; |. L* }" c' u/ F0 f - //共享内存初始化
+ ?6 \. X4 v+ c8 |; j - SHM_ARM_Init((unsigned char *)mem_base);
5 M, U& G. O( f& l9 o - /*申请中断*/! W. o6 a$ N6 N
- " h" X# L* @+ s4 T# Z
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);
* s s# v p, B9 l# L! r1 O/ k2 Z } - if(result != 0)
4 a1 i/ Z2 z! ]& W - {6 P# i; F& E" j9 b
- if(result == -EINVAL)( G2 f$ I2 F- X+ m
- {3 u/ Y7 X( ]) |* z: o5 u2 k q
- printk(KERN_ALERT "irq request err:-EINVAL\n");
- i9 _ Q! _- ^, B - }
% \$ ?; V# ^, E" @ - else if(result == -EBUSY)
, _7 \# H$ |! P* S- z/ k - {
4 o+ I+ u+ N9 d$ X( u1 b& }/ H8 w/ Y% i - printk(KERN_ALERT "irq request err:--EBUSY\n");8 W: R( C3 A/ Y8 g* b% d8 a6 F
- }! r, W7 n$ o! p$ h; G7 x8 r2 ~6 `1 T
- else, `( Q: \8 u8 A* s# U
- {
3 C& c3 Q" x8 E: f6 x& f - printk(KERN_ALERT "irq request err: unknown\n");
6 _5 Y! l1 a) G0 H7 s. z - }
; P. K& u2 E) B. J - return result;
7 k" D- R7 ?8 I- f# [ - }; f% _0 l1 ]4 L& ^# B! C0 |6 J
- return 0;, B; x7 v1 t+ b
- }* e0 p+ U8 p8 {& t+ b
- 2 h* {7 ]3 ?) \) b0 b( u
- /*设备驱动模块卸载函数*/1 e! t+ j0 \% n" s6 Q3 k2 s, y
- void __exit protocol_exit(void)
# V4 F" O$ h: o t+ a2 Y - {
/ |6 w, \9 d0 N& r( X - /*释放中断*/ @# Y7 |! w$ S1 [ R
- free_irq(IRQ_DA8XX_CHIPINT0, NULL);# U. p% Y1 l i& C& P* @# I+ p" p
- //释放帧缓冲的内存
I1 \! l/ w& h( O Y - k_linkQueue_release(&queue);
8 s% o2 x* {& \+ Q4 M$ U - //释放寄存器映射
; {3 d: P3 w" ~! A" Q - iounmap(R_CHIPSIG);& ]3 w7 X6 S% p- @ e
- iounmap(R_CHIPSIG_CLR);
: a% p. [ W3 K" x - cdev_del(protocol_cdev); //删除cdev/ Z- q8 X* o0 I- s, N* g- A6 i# D% k
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号9 O0 q( {1 r0 n8 N6 _, D6 K- i) v
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点) M: k5 z$ B# @# O: m, j+ E
- class_destroy(protocol_class); //销毁设备类
# x$ T8 y/ x* S - printk(KERN_ALERT "exit success\n");
) `0 g" ?0 L+ ]" N0 g6 O - % { Z1 g2 z" H4 W# i$ f& r1 d
- }$ b4 N2 x! R0 o8 m
- //驱动其他部分省略
复制代码
8 F( C9 z1 T3 ?5 |+ }6 O" J! A" Q- H/ g+ P3 L7 Z" O. ^
|