本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑 . A1 Q4 n- r ?" L
( D" {; ]0 k& Y( k( m9 d1 W9 A
项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略2 `4 k+ N3 }2 ?+ ]0 |
- * B' U4 F1 G, O4 Q* z; c
- //引入其他模块函数和变量% v6 d* f0 g! t
- extern Ping_Pong_Buffer res_buff;
6 s7 p; x" i2 h. O& x - / }) x6 s5 b( U# S9 F! z0 s9 P( P
- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列# _% H+ L! x# e" S
- extern void k_linkQueue_release(linkQueue *queue);//释放链队列
4 G4 J* D8 ?) F, B+ v* l - extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据
+ u; B, u3 J- l, e+ n" ?" \+ h - extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据
4 ~; z4 `: G9 C, E8 O - ( u; A% M9 D* H3 J
- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化- @+ _7 V5 p7 G/ U
- / S7 h+ [0 Q. V8 f( m e
- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1
$ }) @$ [- c) m9 a) C: s - //设置主从设备号
! c& @" a; K& o/ g% g" } - #define PROTOCOL_MAJOR 1
& {, K& h" m6 i' N+ G - #define PROTOCOL_MINOR 0/ C: x& D- `- z/ a3 h1 Y* X
2 r) x) {6 s# M2 r, a, a7 @* h; s
/ c4 {! @4 O' }( D* d. {, T
6 y1 O. R; z1 l- //定义设备驱动的名字或设备节点的名字/ a2 }) U* `/ Q7 O: P( w
- #define DEVICE_NAME "protocol_driver"* \' e3 g% B! u2 _) g, K0 E
; [! m9 _9 C. _- a# k( u- ! _$ Q- T N7 W0 J; _
- //定义全局的循环队列作为数据缓冲区
' z& Q( a: U1 T8 f' b5 m - k_linkQueue queue;( n* b' \6 d+ p( O/ c+ h
- * D8 |! X' e4 f }2 w
- //寄存器地址映射全局变量
2 T5 G7 n6 D( M$ j. u5 q2 V2 m$ C - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器
/ I+ d4 K) Y& ^- W9 S' u - unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器
% X @! @5 A" w( E
' ]) ^ x$ F$ O3 l W/ P \, X- //物理内存映射全局变量# z' M9 [# U5 h# m
- volatile void *mem_base = NULL;# f# \2 g ]% F9 v4 ~) P* a
- volatile unsigned char *cur_buf_ptr = NULL;1 {/ [2 G0 C- H0 f B
- volatile unsigned char *data_ready_ptr = NULL;
- r9 f% T2 G6 H* m5 _5 G$ U
8 L) q; F6 b# \ N4 t9 ^
; `, s4 w3 `. [- 7 \" o2 ^1 `& p$ {; k/ @# T
- //定义读数据等待队列头,IO阻塞
( S, ^" L6 Q- ]5 M1 [- K - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);0 S% b9 o& M2 ^& `9 G0 z; h$ s
0 C2 h0 }5 R, V Z( g6 u' ~' [- //定义原子变量
' M& I+ k& ?6 s1 |5 c, s - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备4 m/ W. {9 H/ l6 j0 ~# b$ s: `% I
- 2 M8 @# U4 w& I3 S
- X* F4 D0 T4 y% H
- //定义设备类
0 @; B' ?7 W' g5 Q5 T& @+ k - static struct class *protocol_class; W1 \) i3 W7 j9 n P( D# J
- struct cdev *protocol_cdev;
/ A& e# t) |' \ - dev_t protocol_dev_no;
5 m: H% I4 i5 X& [ - - E" ~* a Z6 T
- /*定义tasklet和声明底半部函数并关联*/+ S+ ~! d1 p# Z0 K
- void read_data_tasklet(unsigned long);
! S3 L! c; o* M9 E4 ^' G8 d1 K ?) `
. p& ^5 R2 V1 E* t+ a$ e, G- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
1 B# ^8 ]+ k" l - //将CHIPINT0_tasklet与read_data绑定,传入参数0
; s' V# k0 D3 w* P, T8 {) _
, s$ R8 G' |2 e9 R* T. ~$ @- /*中断处理底半部, 拷贝内存*/
( }" Y* ?: _! O) h - void read_data(unsigned long a)% K% u0 U3 ~; j8 i _
- {0 q0 Y$ P9 p1 q8 y" t1 j
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1
4 e/ X/ D# i3 ^9 r R- E - {* g! m6 @& T8 W* k4 }
- read_quest = 0;. @+ s2 `: o& h
- wake_up_interruptible(&wait_queue_head);//唤醒读等待队列& b% T8 {/ X2 z& ], Q7 a% Z" C& G
- }( H- r; l- U# B/ S( O( }
/ D3 @' l' Q% I- }: o' \& B5 u( x0 t4 ^" j
- 2 H7 p6 b9 q! }, j
- /*中断处理顶半部*/( C$ b+ [& \& R' K# L" }5 N
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)/ |/ q+ M1 s2 s4 p( K) u# L1 V0 y
- {% p3 L0 t* Z& N ~/ w
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样, }9 {, x& f- H0 o
- volatile Buffer_Type *next_read;1 i. s: J: d: O$ u- F8 K+ L5 C
- //如果DSP数据已经ready+ ~+ ^* u8 }4 x7 V9 _
- if(*(res_buff.cur_buffer->data_ready) == 1)5 z6 u* L! H2 x. D; X9 u& H
- {- m( U. @! } U
- if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer
' c4 @) t; c1 v - {9 q; Y d! J) m1 Q" a; B1 U
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer3 ]) X# }! b* V4 A
- //printk(KERN_ALERT"read ping\n");
2 z! v$ [, ^- f1 ]7 T- ^ - }# v0 i L9 w; [% S5 p; V& Q8 g' T
- else$ b9 q7 X: {9 `4 `% y6 f
- {
" I9 b- m' X5 v- l) `! { - next_read = &res_buff.ping_buffer;//下一次中断读ping buffer/ u9 D* [: x$ J
- //printk(KERN_ALERT"read pong\n");4 F8 ], e' w, X" ?
- }
) q4 r+ U8 M) r* o4 f0 u. \2 p7 s. @ - *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer
$ j' r" V/ t3 J$ ^ - //将数据插入链队列
, L$ e* m7 }4 ]& e+ t* o - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);
5 W9 y1 z+ A, J. G+ t - //标识位都重置
4 y0 o- n/ b. r4 b, z" P9 T - *(res_buff.cur_buffer->data_ready) = 0;
+ c K6 u# ], {9 E2 c - *(res_buff.cur_buffer->data_size) = 0;0 w! u7 [: x# @$ }7 q8 y, G) H; W1 V# }
- res_buff.cur_buffer = next_read;4 e- P6 L( O. P/ Y5 \8 u0 |- j
- }( u" m5 D' P: I0 G
- //清楚中断标识
" i4 `3 y0 i9 z& w$ ?9 B) G - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status1 {5 p; q1 g/ R* U* {" d
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部
9 ?8 x! S( l: r) G
2 z" Q- t* z" F9 @
4 @( ~8 w4 S3 K2 [3 y- return IRQ_HANDLED;
/ L, i7 K8 [% E - + W7 v0 u# O; z h$ m) w% L
- }' N* `7 n' I, U( t/ l
& A, u$ V+ Q8 C) j% o+ {, k8 Q/ z- //文件打开函数9 [# Q+ A/ N$ a, e
- static int protocol_open(struct inode *inode, struct file *file)
/ ^* f7 H9 G1 p, k! G - {8 X$ u( x6 F1 T3 k. L {
- int result = 0;) ~+ k6 B1 i, @
- if(!atomic_dec_and_test(&dev_available))5 R1 X3 L1 T6 {" \6 q; R2 \+ X
- {
. _; U& f! i3 u+ S3 P - atomic_inc(&dev_available);' a9 r {: s* m2 `
- return -EBUSY;//设备已经被打开1 h! d7 R" ?, _8 ?/ i9 z) W
- }
) E. E8 V. g# ^ Z0 K& U: G - printk (KERN_ALERT "\nprotrol driver open\n");: c- J5 [/ ]/ o- }% _2 q
- return 0;
) z5 ^ S x: o# i7 {. |% H - }
0 J3 m9 h% n* l9 m t - , H$ m5 t3 @ a/ P* a% D
- //文件释放函数
- x. q+ O# f" U# m3 x- J. } - static int protocol_release(struct inode *inode, struct file *filp)
T% s# c- C! Z8 k5 y; x - {; K7 l7 X2 }5 b, g
- atomic_inc(&dev_available);//释放设备,原子变量加1
$ o4 @, k' u4 ~- G) l, J - printk (KERN_ALERT "device released\n");
: l* x# U3 H4 Y - return 0;
' J& d' p9 F" y2 W+ U - }
5 l- d0 L5 r \, y4 t( O1 _
! O0 \, c f! u. q) p+ j- //文件读函数7 u6 d! V# c( V: x; d+ U
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)
# n3 F2 W' Z- t1 m% K. o - {8 f3 M/ M7 e& g8 w6 b/ ]
- int ret = 0;
# t* Z0 S7 J# A( B! g - //定义等待队列
3 L$ Y' G2 S+ O# W( q! d" L$ o - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列* t9 b K; P$ s
- add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
( H. l7 e' ?4 P: h' ? - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据7 A, c% U8 X$ |8 D8 t2 [) f
- {
9 h+ Z. \, Z& R) a' c/ r - //printk(KERN_ALERT"\nbuffer no data\n");% q2 l( Y. w( ^; ]2 G, A
- //如果是非阻塞方式读取,则直接跳出
w+ ^, B5 f' x9 B- O - if(filp->f_flags & O_NONBLOCK)
/ f9 Z/ S& B& t1 |7 k - {' b$ f. Q6 _2 G4 A. h# q
- ret = -EAGAIN;
6 ~! ?1 V6 d7 h" G. |8 x) q% a - goto out;4 J/ a; p4 [; k' O- U
- }
- f9 d# \3 ~( W; q* {; ^0 j; k - //阻塞当前进程,放弃cpu资源
1 r& u: `8 X8 y8 J3 G. O - read_quest = 1;6 |( w0 g8 z0 d) J+ B
- __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠
1 H. e) S8 g/ e' g! q e) E - schedule();//调度其他进程运行
4 K2 m6 L! j. |$ f& _6 s - if(signal_pending(current))
* @! T7 S8 n9 A" u4 v0 h - { [ @* l6 W8 d2 m+ ]! ^3 o
- //如果是因为信号被唤醒,则返回到系统调用之前的地方
$ t6 j+ F$ E* @/ m) q# Z - ret = -ERESTARTSYS;
% `. ~( B7 i P: Y' E& l: c9 K - goto out;
6 ~. B6 c3 D0 ?% D2 A5 Y - }4 `* N, P$ l/ F1 b' N
- }
9 m- A1 Z* {, X$ ] - //将数据拷贝到用户空间& D/ X5 L4 c. @$ G V: ^
- ret = k_linkQueue_getData(&queue, dst);
6 m$ g7 e' Q9 R - if(ret == 0)
+ ~$ T8 i9 o1 `* X2 n/ c( c" w2 e - {: A4 y0 X! b+ h% y+ x/ D
- //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
& d$ D/ x7 ^' l, _ - }
. u) o5 W( {+ c- ~8 ] - out:
, Z# I* ^: p- U - remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列
( c, s3 t4 C" X/ N8 w' N - set_current_state(TASK_RUNNING);//设置当前进程为运行状态
J( i; t# Q3 o3 x- X9 l - return ret;1 ]/ A& j! h( }
- }( }) @5 P9 E5 _' x0 J
- 6 [% B+ Y# f$ h! N# R- _0 U
" l! N* {9 B1 \4 |- x- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)
+ \) T0 g5 m8 I2 j% a X - {
1 S- U- Q) ~3 g - return 0;5 D4 _+ S* I3 d# N7 J2 }" z+ h
- }
+ p2 y+ Z k+ }+ G! i - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行, _* s' e; w0 f' u5 U T1 T. v
- open()、release()、ioctl()协同调用时被调用*/
9 H9 n3 Q% p+ C9 H$ z - static const struct file_operations protocol_fops =$ r1 f6 \, A+ \% h% ^+ F3 ]
- {
. p" r5 L$ j: ?' Q - .owner = THIS_MODULE,
9 u( m. j) F' g! D - .open = protocol_open,
d ?# {8 c' K, U A - .release = protocol_release,
2 w& \1 [3 d( n) h - .read = protocol_read,
. l) P$ Z/ D" K) N/ i8 u - // .write = protocol_write,) g$ N3 d$ E6 C8 U( n: F) {9 G- G9 B/ w
- .unlocked_ioctl=protocol_ioctl,6 q' \' C: ^) ?' f+ D7 t) @5 t
- };4 f" N; S& z7 g" H/ |& U+ l' e; y
- . w7 v$ d4 ^9 W$ Q/ d* a8 p( q) ?
- /*设备驱动模块加载函数*/
8 W" v' u1 N5 `& g - int __init protocol_init(void)
4 _9 G8 y. Z: g - {
( h, P% }6 F5 F, H+ m7 z - int ret = 0;( o- g' z. f5 L) F1 [2 }+ x
- int result = 0;! \* Z" D- m" _, \
- //申请注册设备号(动态); S! @5 o9 A' }3 u" R
- ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); & {, r5 A- c R' G" ?6 J& M5 ~
- if(ret < 0)2 p+ B. `0 ], M% F4 j4 s
- { l0 c7 D% W% O8 {9 p# P# {1 I
- printk(KERN_EMERG "alloc_chrdev_region failed\n");' I+ {2 }0 {' d/ |) P3 P k1 W
- return 0;+ D4 {* C- w6 O3 _* ]# G
- }
9 I+ ?2 \. r1 x2 A) D - //分配cdev2 l% ], {( `+ Q' w3 T) }+ A: X
- protocol_cdev = cdev_alloc();
8 t ?; V4 P9 w1 Q4 g( [% K - if(protocol_cdev == NULL)
4 n! @5 ? u) ]; ]' Q - {0 z/ V/ E) M5 y
- printk(KERN_EMERG "Cannot alloc cdev\n");- W: E, Q& W# D; f4 _
- return 0;9 F9 a! g7 ^' M, b! I* V
- }& K; a# a# A* u" |: J" w
- //初始化cdev6 J6 Y' o r7 p
- cdev_init(protocol_cdev,&protocol_fops);
2 l' h: Y T; a( \- h3 @/ M9 }% k - protocol_cdev->owner=THIS_MODULE;* ]; `! t y& {5 r+ s6 W
- //注册cdev- o7 Q3 C1 H1 D) J9 s
- cdev_add(protocol_cdev, protocol_dev_no, 1);
' v* ?1 @8 X" |6 [ - //创建一个类
, T6 ~" C5 b7 [" O9 g, s - protocol_class = class_create(THIS_MODULE, DEVICE_NAME);
$ O7 ?% h0 w: [" ?1 N }) K" @ - //创建设备节点 `- q, U% ]+ a* G
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);
5 k2 O: }2 Y8 Q0 F$ x - 9 |& j- W, n* d! ], R0 _: T
- : X! m9 K3 i ^$ B
- //申请链式循环队列作为缓冲区DSP数据帧的缓冲区$ e3 e7 y: H y0 O* c+ F3 C: g
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区
6 z; v ~: ~3 o) b5 Y
r) v( h1 t6 B7 v7 v- //映射ARM的核间通讯寄存器
$ x& P9 A* ~% o6 F8 K - R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);2 s! l+ a* w- d/ ?8 K5 `! h
- R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);
8 j( s3 |' D2 ~# Q2 }9 _' ? - //将物理地址映射到内核空间" u. |% H" i9 \9 i; k
- mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);& j% }) S) F3 e r" d
- //共享内存初始化
/ K- Y* [0 B' f& o% ^ - SHM_ARM_Init((unsigned char *)mem_base);
- g9 t! j/ g& z3 `* L - /*申请中断*/
! N5 R1 J& R+ Y5 \) V
2 l" V$ ~( G* J/ Y- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);2 z( \- V$ U5 n
- if(result != 0)' T' r8 `2 [/ c4 E- p$ f4 x
- {
7 ], E+ S, f& J* N - if(result == -EINVAL)
7 o& ] @. |8 u! [/ x9 i9 @7 n - {: h! |2 {( r+ V" O* M$ B/ u" l
- printk(KERN_ALERT "irq request err:-EINVAL\n");
% t& V3 v) w p% X0 t5 { - }
. A4 ~" X4 K; p- a - else if(result == -EBUSY)+ K& u6 s: k% H
- {
. Z3 x/ h+ |- S6 P - printk(KERN_ALERT "irq request err:--EBUSY\n");: f, f2 f# x* B/ M" W1 E
- }
4 K, y4 g& d5 E - else
. x# p0 h8 k2 n, Y: m - { Q1 J7 e4 }( G( Q$ N9 \! y7 c
- printk(KERN_ALERT "irq request err: unknown\n");
" I1 _; ^; N: \2 [6 d6 f: a - }
" ] q0 k9 @3 o( S! n9 Y3 y, _8 s$ _' L' U - return result;
1 }3 ^; }* U" ^9 d - }
* x- `' d$ {8 x, `; ?7 t - return 0;4 [# ?- V- @; N4 p% \
- }
9 ]- D, \, A) I9 q' a, K - & E' H3 i) i6 ?/ E4 g- ~
- /*设备驱动模块卸载函数*/
9 B2 T4 H; h. R' ]# s' S - void __exit protocol_exit(void)$ k4 F+ i( D/ z, e6 V# h: f1 Y
- {
8 w; g) {' C a. e) X - /*释放中断*/ v2 C4 s* H4 a2 |" G5 M
- free_irq(IRQ_DA8XX_CHIPINT0, NULL);
, d0 x& [) t- O3 ]5 x: E - //释放帧缓冲的内存
% q' J: Y+ o$ p" J( a4 A - k_linkQueue_release(&queue);
5 o8 t* I5 y/ s5 r( A( L6 S0 G - //释放寄存器映射4 q& S# O* U2 h- q1 D
- iounmap(R_CHIPSIG);1 `6 y0 b( t* d& `( a
- iounmap(R_CHIPSIG_CLR);
3 O. y% P- J8 m9 ~ - cdev_del(protocol_cdev); //删除cdev
% @7 T t, n" w4 ` - unregister_chrdev_region(protocol_dev_no, 1); //注销设备号
: B. [2 A8 V1 t - device_destroy(protocol_class, protocol_dev_no); //销毁设备节点0 N% Y8 v3 W Q5 N
- class_destroy(protocol_class); //销毁设备类
% B: ]3 z- a/ u - printk(KERN_ALERT "exit success\n");
* s2 h, Z; v- v7 Q7 r - : Y* f, g3 p9 I: d8 E; ^6 v
- }
6 N! L/ o Z2 F" ^: p7 }& o" u - //驱动其他部分省略
复制代码
. @3 H" t+ A; R
- Z+ `+ r! G) _) D% L |