本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑 7 g/ _, k" q& x2 C1 o4 V! r2 O
9 K1 Z9 V% v) N. h* `% _7 b f
项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略+ y3 C0 C6 R/ o' ~ [
4 L* p, Q3 S* X" b# ~; p- //引入其他模块函数和变量. P8 U9 |/ e. B/ a' ^
- extern Ping_Pong_Buffer res_buff;. R0 V/ Q/ ? v
! @5 e( x: l( Z) {' s/ [- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列
5 P8 Z3 w" v" W3 w - extern void k_linkQueue_release(linkQueue *queue);//释放链队列+ k/ |' ?. f r: s5 a z
- extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据
. @( i4 P6 [0 a5 K# b) a/ J& G - extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据
0 @! ~0 }# n" d( R7 `8 c - 2 w* I+ h! T. d' [3 a$ Q/ F* I
- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化
o% b% i% j* p1 ?. h% I - : x- o, L4 n1 d3 e2 ~
- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1
8 _2 i. S. l( B! @; t& ^ - //设置主从设备号
8 `& K) M. x" \ - #define PROTOCOL_MAJOR 12 J2 D8 Y H, T% m
- #define PROTOCOL_MINOR 0
z x' Y- m/ D1 e
3 y$ C5 s1 K9 S+ N: q6 m: N- - F3 N7 W0 G& C. H- T( U
5 k: J2 J8 l: x l4 f- //定义设备驱动的名字或设备节点的名字. B% n, d* l* Z( }% T' E6 H
- #define DEVICE_NAME "protocol_driver"& O4 ]( T, E/ p1 B5 f) Q
- $ {* g+ `) [( e( g- l8 G
/ h" r/ H- R- i7 v, M2 K B4 u- //定义全局的循环队列作为数据缓冲区
5 O" w. w, d I3 Z' h" ^8 G - k_linkQueue queue;$ t: R/ p: n/ Z( T) ]
+ l; i) z; B9 ~+ m+ [- //寄存器地址映射全局变量
9 T! n" T8 n5 z5 G6 u; U" P - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器1 F) C n1 R" D) Y
- unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器8 `3 R+ c, S/ t$ R6 d* i% o6 q0 K5 y
; m, Y! A' h: G$ q) ~- @- //物理内存映射全局变量4 I/ @6 z, j8 T7 @' I
- volatile void *mem_base = NULL;/ H2 o& k! `+ r
- volatile unsigned char *cur_buf_ptr = NULL;
* c \1 v1 ]6 _6 u - volatile unsigned char *data_ready_ptr = NULL;5 [( h. z. Y ]7 M' d" N: }
- + T- {9 p5 P2 {& e$ W* H# v( T) B
2 y5 L( u5 h5 |' \- W; _
( J7 s R( Z2 l' H C4 } c- //定义读数据等待队列头,IO阻塞9 R2 ~! Q- e0 T! O: H# \
- DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);3 {6 l; A- }: f# U' J% m
- ' |5 i! f$ y S0 |
- //定义原子变量
$ q' b" Y! P9 }' v1 o: ^. l - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备$ R* X* u- |9 n
- ( b, W; \* M. n! h: }
8 G) ]3 ]$ C1 y, A" u0 R: e- //定义设备类! t0 @ Z. j) ^2 k* i* h" ?( a( E
- static struct class *protocol_class;
5 o2 I. z7 ~* A+ Z, L( C5 Q( | - struct cdev *protocol_cdev;9 Y2 f4 v4 X) u S; L R& x- O' c" p
- dev_t protocol_dev_no;
* Z8 o4 K. Y3 k0 _ - 4 R, O& h& A& x$ O% `, q- X A1 J
- /*定义tasklet和声明底半部函数并关联*/
8 @1 r0 Y& s2 r, B( Q3 S9 I J - void read_data_tasklet(unsigned long);9 m7 |* U' h; B* ^( u3 d
- : m# y' u8 \. X* k' L
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
! G% Z# C4 w: S; X( P) n. F. q - //将CHIPINT0_tasklet与read_data绑定,传入参数0
1 T1 R" U* r2 X+ u: a) ~2 \1 Y
$ Y. T; T. r/ u) x; H- /*中断处理底半部, 拷贝内存*/$ v/ ~/ t% B1 a! d
- void read_data(unsigned long a)* D( G. G8 l: x4 {8 p
- {
0 s( `! N. e4 g - if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1( U& y3 J, Q1 y, p8 X1 E0 {
- {
6 W" W7 |) O( t( o - read_quest = 0;- a; @& ~$ [3 x0 B
- wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
u0 u+ i! M) h- T& ?/ ~% h' ~ - }; g& ^! y' c* m4 L
: S: X/ O/ _, y# b; h1 H' h- }8 J; P7 j8 R2 N
- ; g6 F5 c: |: x) I. B, z' m
- /*中断处理顶半部*/; l$ C6 A7 P/ R& ?9 q
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)0 i% W3 z9 N- _0 x+ Q
- {
. d# A4 A9 F) ^$ }# q1 O+ }$ ^/ u - //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
) F5 h3 v. S+ f# c h- q - volatile Buffer_Type *next_read;* b, s) J; k) E" q; \
- //如果DSP数据已经ready
1 S- F" ^/ h( q9 _ - if(*(res_buff.cur_buffer->data_ready) == 1)
" K8 J+ T+ c% g - {& g, D' `# R: E" C8 R: ~- a' `
- if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer
0 u9 B" Q. F( G* c8 [; y - {! c4 |+ R& v+ Z& i$ x( h
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer
+ Q( k- I" F: x) f: L: o1 P/ X - //printk(KERN_ALERT"read ping\n");4 I) W5 f& j' k$ g1 n: V. ]
- }; K8 {7 d( k) E+ ]8 \) d
- else
# @1 q {. p9 h6 X7 P3 r - {7 t: U- X; c1 s |0 K5 O) [
- next_read = &res_buff.ping_buffer;//下一次中断读ping buffer; q. Z8 _1 }6 v4 f' ~
- //printk(KERN_ALERT"read pong\n");
( L( x9 S, P# r, I& \# w; _ - }
9 \ \" y2 r+ w4 v" k3 h0 j - *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer6 ]9 x1 l+ T# z0 B# n S
- //将数据插入链队列
9 g( q( k8 Z6 E r1 V* S0 Q - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);2 U: z2 \% h8 o* y; d& t" d
- //标识位都重置
8 m" n5 [: K d - *(res_buff.cur_buffer->data_ready) = 0;6 y$ q) i: D" x; |
- *(res_buff.cur_buffer->data_size) = 0;
, o2 Q, ^$ t0 x - res_buff.cur_buffer = next_read;9 b' x" m. w' Y; D$ i& T- s
- }
, S+ {' E6 }+ ~; I- J3 z: e - //清楚中断标识/ L( g( R% i' B' U
- *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status( Z- r9 P* V+ A& Z
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部 ) e3 q* t) {1 Y& j0 z
8 I8 I/ j& G8 v9 y
5 K+ X: U |0 d+ N- return IRQ_HANDLED;
5 r' F3 a4 t# Z' ], `, Z/ t' j
7 g; ]4 b( a! E- }. D" N' V1 U Z* F- a) @
* s \" J9 m$ d5 q- //文件打开函数
9 h/ g) U: _. I' \ - static int protocol_open(struct inode *inode, struct file *file)9 g8 x Q" A- g' `
- {
- z( Z7 W( W- e2 Z# y4 _3 P0 m6 L - int result = 0;
+ Q% F. F0 ]2 u9 E; X1 J - if(!atomic_dec_and_test(&dev_available))9 P5 q& O- V4 Y) O
- {8 D" D* f$ N; I( b( g9 T, A' I
- atomic_inc(&dev_available);
5 v: N, L. u7 N, n" U5 t - return -EBUSY;//设备已经被打开
0 E8 C6 x1 t& O% D+ P$ {; m - }( g& n; f0 D: f5 t, U$ a+ m/ e
- printk (KERN_ALERT "\nprotrol driver open\n"); ?) y. O8 @6 j% F0 \8 m* R
- return 0;7 ~8 }+ Z* B' K9 \. R+ G
- }, X, Q7 Y6 B* Q
5 s7 l: b* ]- Z3 h- l" t! B7 K- //文件释放函数
5 w5 Z$ ?: h' n+ _& f6 k5 B0 O A2 k3 d - static int protocol_release(struct inode *inode, struct file *filp)1 T/ i- L' J6 P- D' E. t
- {
- C" S/ Z7 `& g0 | - atomic_inc(&dev_available);//释放设备,原子变量加1- e7 Z, W% o' e0 J: R6 U: q
- printk (KERN_ALERT "device released\n");) q) `) T y2 `& q& F
- return 0;
* l+ d( }' j* v$ ~/ p: U, _1 y - }0 P% `, |1 ~1 b3 H' D
- 7 d0 w7 _* |; r1 \8 V* z
- //文件读函数' [: H/ R$ c3 d$ V
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)* N5 @) y' B$ Z5 Z" ]
- {
0 e4 o' Z7 }' n) | - int ret = 0;
4 J2 _* l4 s$ ]; ?- |& U - //定义等待队列
6 c4 y" A& Q/ F) Y5 r2 B - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列
2 V) c2 u1 l" S; s X) o/ e% { - add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列4 N7 T$ I* B0 j# R( T
- if(queue.remainNumber == queue.blockNumber)//当前buffer没数据6 o0 x6 e/ A4 S8 ~6 c: F
- {
* _ `+ y& _9 Q1 F6 m# K - //printk(KERN_ALERT"\nbuffer no data\n");
# \# L! j; c0 A9 j x$ Z% Z- W - //如果是非阻塞方式读取,则直接跳出3 N8 D% @8 W1 W! p- W0 j
- if(filp->f_flags & O_NONBLOCK); L( ~& a p! e t
- {
% ^# R# v) o9 l/ K$ K% u7 o - ret = -EAGAIN;
5 }+ G- f3 {+ E - goto out;) c6 h: E3 I$ B
- }
- |- z! v/ z; S- k% v4 ~ - //阻塞当前进程,放弃cpu资源. E8 l$ B: r1 u2 p, t8 u
- read_quest = 1;. n( m1 K6 t, o: x
- __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠- [# D- p7 |8 u9 M& B/ `1 H
- schedule();//调度其他进程运行$ z6 m+ U" G3 Z+ h4 K
- if(signal_pending(current))
0 @" h$ ~! Q- I8 R* f - {
8 D& D! x( J3 ~ i% T, E( p! _ - //如果是因为信号被唤醒,则返回到系统调用之前的地方
# k+ [- t% ?: l% b- R - ret = -ERESTARTSYS;
; S3 g% f: i' I+ B0 u - goto out;! D! u# Q/ H3 c. j# f& ?/ O
- }
+ u! B4 R% F$ o- j6 T+ | - }3 }# @# k$ S# l k
- //将数据拷贝到用户空间
! k3 N; j( _# j+ M& H+ T" E0 i7 u - ret = k_linkQueue_getData(&queue, dst);' Y7 |7 U! [4 @
- if(ret == 0)8 {* N& ~' n$ s }7 |9 f
- {7 s$ ~1 S- w! e2 @: x2 N* s
- //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
- m7 b+ N2 x) o) b) k - }% u% l* ^# q. g1 k& F U
- out:
W0 x: _; V& A( n - remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列5 i `# t1 O8 O( n( a5 t
- set_current_state(TASK_RUNNING);//设置当前进程为运行状态* G! k+ n' n9 h
- return ret;
' H7 N0 |7 Y0 X% n - }2 h; R4 A, K3 z& k$ e
5 s, `1 [* x; }' w+ S$ q
) A5 P0 P- ~% A; f& Q- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)
* R5 Z9 \, N1 u9 w, U - {
5 I. J+ d+ L- c, M - return 0;
$ f1 ~) Z' ?" H4 ]$ G" r% K) |+ [6 Y - }
( {8 j; S0 W. z2 Q2 j - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行9 w. a8 ], N9 }! l# z9 G& b7 i7 l u- M0 a
- open()、release()、ioctl()协同调用时被调用*/
6 }4 v% Z$ u4 i K) | - static const struct file_operations protocol_fops =
% ]5 U. x- L4 n. } - {7 z7 X4 E( ?+ b% j0 x0 }1 L
- .owner = THIS_MODULE,
* B8 V4 u1 }" G0 m. o1 }5 T - .open = protocol_open,$ l% B0 W; s/ h. B: D) S7 v
- .release = protocol_release,
- ?2 _; @6 }* e1 \' y% s8 V - .read = protocol_read,! }; J& d+ Q1 m6 ?/ x
- // .write = protocol_write,
) G8 u8 a# s n& U2 @& ^5 Y& D/ t - .unlocked_ioctl=protocol_ioctl,
, J4 i( z- g T8 w' m* ~$ Q0 S - };1 e1 e6 z8 c; T# A. t. h
+ n- f6 n3 D7 l8 W- /*设备驱动模块加载函数*/. v! ?2 I/ @# \- x5 z" h
- int __init protocol_init(void)/ Q. S- N! h4 u o' X1 T0 I
- {& m( o- g8 f. M
- int ret = 0;
3 l w, Q/ l# T - int result = 0;
3 a. I" |# W7 Q2 v% \% c: S - //申请注册设备号(动态)+ L# d& |6 G- B8 N5 x& A
- ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); % h- @0 L' _ |5 o, B2 ~6 o2 O
- if(ret < 0)' e8 e: m% S8 @, W& ]8 v
- {
& s" q& V0 f: ?: ~ - printk(KERN_EMERG "alloc_chrdev_region failed\n");
; o. ?& R6 e. m- s. ?. {2 l6 g - return 0;
8 _: p6 G' f& k - }7 w: E+ e7 U( ^) i9 z, |/ A- G
- //分配cdev l$ W6 ]& z* O8 [" b1 y! R' K, t
- protocol_cdev = cdev_alloc();8 T8 Z' W: _' I9 S
- if(protocol_cdev == NULL)% a& L* Z4 l; Z# f* G
- {8 K9 g2 n, G9 x; G) ?3 f( e
- printk(KERN_EMERG "Cannot alloc cdev\n");
4 ]& I- g ` P$ o/ l# R0 S - return 0;, r/ z) S$ E: |( [% n
- }0 Z! L7 @2 e3 S4 v8 C
- //初始化cdev( J; o" i$ N/ b) \1 D/ g
- cdev_init(protocol_cdev,&protocol_fops);$ a4 }5 [6 J' T5 ?; n
- protocol_cdev->owner=THIS_MODULE;
5 Y2 }: U9 f ^7 ^5 Z% O - //注册cdev
, o, Y! d, ~' n- m T/ l) W - cdev_add(protocol_cdev, protocol_dev_no, 1); & D9 i7 {$ z, [
- //创建一个类9 k+ d) L! c7 O
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);
0 u# T$ c# U4 m' y% H8 ^ - //创建设备节点4 p8 l9 r+ y8 Y
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);
* @, f, f$ S; d& U4 q$ A- S S7 B -
" f5 o0 b4 Y0 E5 U) \" q - 9 h2 k# P7 Y6 {; Q
- //申请链式循环队列作为缓冲区DSP数据帧的缓冲区9 ~) V3 H! B5 h
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区
6 p' _6 w2 | Y( D- F
5 ^1 G8 t+ o& ?" A0 F7 a- //映射ARM的核间通讯寄存器
5 ]$ s$ y7 u9 O( ]4 ^6 h - R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);! Q, h6 ~6 ?* E7 O1 J3 [
- R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);
" c$ h! c9 q- a) ?% n5 U. M - //将物理地址映射到内核空间
* M0 w0 _0 j; g$ \$ z5 ]( d - mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);
: |2 _/ Z! w# O8 k1 H8 I - //共享内存初始化
: a' R/ Z- ^* x, w# v% q - SHM_ARM_Init((unsigned char *)mem_base);$ d& n1 _$ Q, I
- /*申请中断*// Z. Y K8 a c1 v2 ]
/ O' X; I4 z+ y, G- [- k, D- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);
: r9 e, Y5 u$ j. t - if(result != 0)' c' \3 O( j: B$ s, C
- {
. O' ]$ u ~9 s0 K+ M - if(result == -EINVAL)
3 q- M9 N3 v6 d: v* Y - {
1 }# q7 F! y+ g$ O - printk(KERN_ALERT "irq request err:-EINVAL\n");
8 H; J# F7 I8 a - }
. G% W! s2 Q5 h! Z8 [5 W( { - else if(result == -EBUSY)
( }" C A4 R+ u* L: G/ I - {% z8 B7 N/ A \4 {% u9 O
- printk(KERN_ALERT "irq request err:--EBUSY\n");
" e( l3 K+ @& M - }" M- y4 J! }+ A
- else5 {0 j3 }5 I$ M5 w
- {
0 v! V5 W3 e0 p- @; j - printk(KERN_ALERT "irq request err: unknown\n");
( n: x% k# C* g! {$ B - }
$ {6 I1 `- |' L( h G - return result;- D; E9 g: F& J+ F8 F! c' E0 i, f
- }& v6 o% O2 B" }- f0 M5 }
- return 0;
( _/ J& v9 i9 k, I$ V - }; `& N/ n% O8 ~/ K
- # h- k* P3 C0 |& F! c3 e
- /*设备驱动模块卸载函数*/) S$ A! N; k6 b* x
- void __exit protocol_exit(void)
, f1 r3 U- G7 E - {
/ ^+ X! Z7 v/ [# A3 j - /*释放中断*/- Z4 T5 O0 m( n8 B2 `' c! K
- free_irq(IRQ_DA8XX_CHIPINT0, NULL);
; X% j9 E/ v* L. W3 m5 y - //释放帧缓冲的内存
. @/ f0 k; ^$ J: Z0 @ - k_linkQueue_release(&queue); |' _6 @1 W# f" W% v
- //释放寄存器映射
9 V1 ? |" V+ w - iounmap(R_CHIPSIG);
9 u" C7 V/ p7 a, o, q2 v! ` - iounmap(R_CHIPSIG_CLR);- u3 `6 z# Q; N8 N2 [/ l, O
- cdev_del(protocol_cdev); //删除cdev
! L1 r/ V) a* I7 E4 ^ - unregister_chrdev_region(protocol_dev_no, 1); //注销设备号! p0 L$ \, V; m- T
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点" D' o* t1 @, Q% r3 k6 j
- class_destroy(protocol_class); //销毁设备类" l3 U/ s* d5 C. v* C1 N
- printk(KERN_ALERT "exit success\n");
3 H1 I3 |( j# F
2 e# @! p* r7 _* H- }8 D# p' n9 S' W0 t4 ?
- //驱动其他部分省略
复制代码
; X" k$ n5 |5 _3 v- g' E! H
0 N. Q; w9 C; @3 s' M% S Q# r |