本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑
* r, Q4 z1 x. ], [, u; G+ n" f2 O* V+ X/ ~% ]
项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略 T) h, g# q( P! V ?
" b3 x% T1 ?, `! {4 x8 p- i" c) V- //引入其他模块函数和变量
6 h: ?) }8 V/ m/ {; _3 F% ^ - extern Ping_Pong_Buffer res_buff;
3 f8 `1 a0 ?1 C
, g! s( y( i- v2 X; D; z8 i2 p$ J, e- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列
4 }: V3 ~- ~ O! i# _! R- M - extern void k_linkQueue_release(linkQueue *queue);//释放链队列
$ V( m, j0 W2 {" [( G' Y - extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据
. \# M( k9 F. |4 _8 U9 A; O9 A - extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据
: @ W& h- v; a7 O
% q* n1 x- A: z- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化
! E" d7 G$ j' v% V! z
( W7 T4 R" N. i2 e- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1$ t2 O+ F2 K* d& Y& Z& q! q; Q& G
- //设置主从设备号
; G8 g' z% s% J* ?+ h; P - #define PROTOCOL_MAJOR 11 @# @ e; H1 [4 k+ k
- #define PROTOCOL_MINOR 0: N4 @. O$ _6 `
- ; g% i1 Q" [9 d
- ) B/ T: r! h& }) D
- 7 j) m- Z O! w* t4 q
- //定义设备驱动的名字或设备节点的名字$ C/ k- l6 f2 l, q6 t$ N
- #define DEVICE_NAME "protocol_driver" f$ ]: g) v' y; w3 A6 @3 _9 D
z" s4 M" v7 y- $ W/ A/ e7 w3 `' g
- //定义全局的循环队列作为数据缓冲区
2 W# B# |, h/ J* @ U: l/ w - k_linkQueue queue;5 r4 Q5 A+ b6 e" R2 K. D. r) D
- " s( X% K S' X4 O0 S
- //寄存器地址映射全局变量
- ^: l4 o* G ^' n- h0 f - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器3 t' g* f; M. ~8 J" L) [" k
- unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器( m6 D, u) X1 |* B
- ! o+ m0 J( f L( y. M
- //物理内存映射全局变量
, j, o) x: h1 m - volatile void *mem_base = NULL;
& Y9 @( }( r, M- D2 K& _4 V/ g+ \ - volatile unsigned char *cur_buf_ptr = NULL;
; p8 d1 n8 k$ ]8 W* }2 _+ P - volatile unsigned char *data_ready_ptr = NULL;5 U! {1 I6 P1 a0 z2 T
2 v6 H. W I5 T: ^: ~
, f o" D5 a8 M; J) M" ]" N
- s9 G# @ l8 ^7 t. }$ l3 D- //定义读数据等待队列头,IO阻塞
0 M1 M* y& Q. q - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);
3 O/ Q. A9 i6 y" f6 E
5 [9 n; s9 X8 L! V' `% o- //定义原子变量
5 Q+ N/ t0 T# @5 d' T) H2 q/ Y - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备
% q8 X) l3 e7 x9 Q
* B+ o" U6 p m& t7 y) C" \
& s5 b+ N9 E- ?" W% h, v- //定义设备类: F$ Q4 V# R" V
- static struct class *protocol_class;9 w1 T- {) I6 y. U2 |
- struct cdev *protocol_cdev;
I9 `, ?- \$ `% M, } - dev_t protocol_dev_no;8 K9 _$ Z" }' ^, P: w% ]: Y3 ~. E
- ; f! I2 ]& j$ P9 S A; o5 a
- /*定义tasklet和声明底半部函数并关联*/) K. m+ E o3 ^. R* G5 D8 J
- void read_data_tasklet(unsigned long);
8 L+ G& W- F' E2 D2 V" }; Q
% E( O8 O5 K- w- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
, _; z: A/ |) N* v9 j8 x - //将CHIPINT0_tasklet与read_data绑定,传入参数0
/ o% R1 w4 W7 u - f# N3 I- I5 O$ \+ _
- /*中断处理底半部, 拷贝内存*/* ]/ [# `8 a; v8 c) j
- void read_data(unsigned long a)
) s' }& G( d6 @: h& h5 Q' i - {
: _4 O) D+ G0 M% I* p* p% j - if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1
. w. u) u: K( X* v1 a' N0 s, N - {' g! u- K$ n4 R; t+ {8 e
- read_quest = 0; l; W: ?6 z2 K2 o5 R2 |8 h9 `
- wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
9 g5 `- @8 |/ H" L6 h% w% S# b - }* R# {- V, E% }9 c
- * n H" m0 i. K7 U, v
- }
1 S/ |+ _, e" ]5 s7 n
4 ^0 d1 ~; K- B" i8 Z) F- /*中断处理顶半部*/3 `0 @3 h: E' d! e
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)
# K- s: G9 T& K$ R8 [ - {3 t4 s6 s( |9 O
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样0 y5 o9 t/ X7 ^1 E8 c7 k
- volatile Buffer_Type *next_read;
" K6 x& I' _6 h2 v# t! f6 v - //如果DSP数据已经ready$ g4 j! h' h, k2 \8 F( R. _. S
- if(*(res_buff.cur_buffer->data_ready) == 1)0 l7 p& B, z" v! v
- {) B) ?- E) _8 q/ g( `
- if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer8 e' V6 T# @* F8 |# a# D
- {
5 F9 a4 n# ~; Q& ^ - next_read = &res_buff.pong_buffer;//下一次中断读pong buffer0 E! c0 D* U) p8 L" j4 Q
- //printk(KERN_ALERT"read ping\n");: S9 }3 y9 {+ ~' Z
- }5 m( y6 R4 T) }. @2 r8 r
- else) V, V. ?+ l4 {$ [6 F% H! \
- {
# k. p y @0 ?- l: u$ u - next_read = &res_buff.ping_buffer;//下一次中断读ping buffer
/ p1 G {/ K5 E+ F - //printk(KERN_ALERT"read pong\n");7 P1 S# @! q% H4 K; R4 E
- }! m8 `* P; X0 \5 V8 S
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer2 k% v2 k. Q- [5 |9 w7 ?
- //将数据插入链队列
% ?. ~$ Q6 z6 I - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);4 H9 |3 y9 {, Z5 u1 }
- //标识位都重置6 n/ J& j2 Y5 X8 l$ Q
- *(res_buff.cur_buffer->data_ready) = 0;- T2 E* u5 z7 x* M2 T
- *(res_buff.cur_buffer->data_size) = 0;
4 H6 k6 G" h$ C' V. z* C7 { - res_buff.cur_buffer = next_read;, ^9 F" y$ K" W1 z3 P I Z+ E
- }
/ z0 }/ f* j' ^8 r, R9 v- N) { - //清楚中断标识+ m' Z' l$ K" A1 w# l/ f) N
- *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status
4 e' k; a1 p1 V' w2 c0 L5 D$ o8 X - tasklet_schedule(&CHIPINT0_tasklet);//调度底半部
8 N0 T0 H9 |2 ?$ {4 T+ ?4 i - ! b! ^8 a$ ]. [- H6 k
- 9 F- i. ~/ q, J3 _. ?5 y, C) H
- return IRQ_HANDLED;
/ r: r/ ^& D8 K - - a) A+ v7 ~6 K. u" Z V1 B
- }
' M: l$ |* v, R$ j9 m+ I - 7 C( S, \! |# N; c+ N
- //文件打开函数
( T" `. N |* ~' `( J$ ~- o1 i5 a( c+ T - static int protocol_open(struct inode *inode, struct file *file)
2 c K& X3 T) Z2 T- i# P - {' _ g) {; i- b' k
- int result = 0;+ d/ h) R- [- H r4 |+ f
- if(!atomic_dec_and_test(&dev_available))2 K0 x" U8 b2 _
- {7 W0 N9 M# q$ V0 S" ]+ P4 ]
- atomic_inc(&dev_available);* I4 g- t) q0 T# f+ U l
- return -EBUSY;//设备已经被打开
+ m1 ]% K, J+ _& F - }
/ f+ R0 Z7 ~9 W+ W6 u d' p: [ - printk (KERN_ALERT "\nprotrol driver open\n");& x8 u L. L* K1 g3 R
- return 0;
+ o* X9 U; A6 A: @4 ` - }
9 g! n# [' G% c! z5 l - , Q7 ?3 ~6 w5 G2 L9 K/ m) o
- //文件释放函数
4 J, M* c; m7 C6 f6 p5 x% r - static int protocol_release(struct inode *inode, struct file *filp)
0 P) h$ I9 \. D5 R3 S - {
n7 r3 \/ Z4 C7 y5 @- \' C - atomic_inc(&dev_available);//释放设备,原子变量加1) M$ ~+ ], @# m0 c/ |6 _- |( ^
- printk (KERN_ALERT "device released\n");
4 G6 y; Y8 k/ d6 Y. n8 J4 E/ J - return 0;4 B& | x2 I- }; _
- }5 j6 N( R9 J9 r
9 y3 v; C- O7 N, `0 r' P- //文件读函数
7 X, F) a- p2 X& k- R q - static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)
0 S1 r" A e# M - {
: d( g& b/ {" @ - int ret = 0;& E2 M! j2 K- \" f1 r& I3 L. N
- //定义等待队列5 N: M8 u0 }( Q
- DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列) ~9 E: C$ g% i; D, H8 T
- add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
" U+ r7 z7 P+ ]6 [. k% H( | - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据" |/ ~/ R# Q, Q4 Y7 h" a. O
- {; G6 {0 d! n4 Y& K6 F' G
- //printk(KERN_ALERT"\nbuffer no data\n");3 f, m8 N6 O2 n" D4 j# g
- //如果是非阻塞方式读取,则直接跳出
& _: _% j9 |( H1 e' m - if(filp->f_flags & O_NONBLOCK)
+ }& u; h5 \/ { M: e& T - {
7 `& _! n$ B' R$ N - ret = -EAGAIN;
. L5 z* T# v( f: E; y - goto out;: t8 F. { z, s: \+ k0 D
- }7 l9 c# V1 i# R
- //阻塞当前进程,放弃cpu资源; C( g! l& _% K
- read_quest = 1;
/ X+ D b6 e2 I B6 O - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠
1 z+ m% ?) Q4 h& Y/ k O" G - schedule();//调度其他进程运行
) T$ ~4 I3 y* u0 ]% v - if(signal_pending(current))
6 e8 X' E& @2 {9 K b! g' y - { Z5 I( U: s! z8 B2 _' G4 p1 |
- //如果是因为信号被唤醒,则返回到系统调用之前的地方
! V/ G" J g& v) q; w R! P, U - ret = -ERESTARTSYS;4 c# {) { x+ O# l1 E
- goto out;
+ J# s; {- B% T& M- v) L - }
* t/ z( V3 r! f. u, Z1 c+ g- C8 O) d7 k - }6 |; S7 g+ c7 T5 k ~0 n0 _
- //将数据拷贝到用户空间
* H/ ^2 b$ ^5 f - ret = k_linkQueue_getData(&queue, dst);9 a( C, o4 K R4 j( a5 M; N2 Z5 J. [5 r" B
- if(ret == 0)3 x* m% N% F3 L- g! ^
- {
% i8 H% q- \) @: E - //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);, A G5 c, A; K
- }5 j7 V) p" D0 G. F3 c; L' E
- out:
; O) t" c& V( m; i( L- v - remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列
* C* w4 [2 [8 W1 I/ [ - set_current_state(TASK_RUNNING);//设置当前进程为运行状态
$ b$ d z' W" ?8 S& R8 E1 K - return ret;
% Z* T% | k7 t4 Z5 P - }3 x _* H- S! A8 @1 r y6 O: l/ h1 y
- - l( h& M& |5 G* d* C
- & ?% t) U) z$ o/ A. @3 ]
- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)6 A) F8 D+ u9 Y, u
- {
# [- @" }2 e1 Q6 o$ O# w1 q* {" W - return 0;% Z1 m2 i( \- Y- a$ b5 P3 Z& G
- }
( B# J E( c; l( ~ - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行( L8 t9 ~# g7 m* Q+ j. Y& v9 L
- open()、release()、ioctl()协同调用时被调用*/$ |/ Z! q i+ y( ~0 `: r) q
- static const struct file_operations protocol_fops =
* _& S% L8 ^' c: r- t. {0 I - {
* L( w9 k2 g& Z% \* L/ y" X - .owner = THIS_MODULE,
( O5 q9 h) k$ d0 C j M' \ - .open = protocol_open,
i/ V% c4 j/ k" e) Z8 l% S - .release = protocol_release,
! P( Q, N: D3 W5 o2 c - .read = protocol_read,2 b% |6 S- |3 L& D8 v' z$ {
- // .write = protocol_write,1 ~( Y* ?+ ~& v1 I
- .unlocked_ioctl=protocol_ioctl,1 _5 u) A, A% u B! s
- };# S. F+ p( C- B
1 X& y1 [ l/ u5 ^- /*设备驱动模块加载函数*/6 i6 m3 H2 i1 ^# R4 Z2 C! U, {
- int __init protocol_init(void)
* w. {. M, t' b s1 M - {; u" o1 B. x5 T6 J8 p2 E7 z
- int ret = 0;* r/ A8 z s' F! g! B+ X4 E) v/ \
- int result = 0;! z, P7 U' G4 F0 [
- //申请注册设备号(动态)
* w' B/ l& a1 | - ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME);
, [4 W- `0 Y4 l& o. j1 c - if(ret < 0): Y% U1 L4 b- f7 R
- {
[/ r$ x! u! |9 [+ b1 C - printk(KERN_EMERG "alloc_chrdev_region failed\n");
2 {( T: L$ m* Y - return 0;4 ^6 j5 B! a& n; ?: y( k8 M
- }
; c9 \9 ~6 P" @' M3 ]+ B( | - //分配cdev
' u2 M% |- C) A# p5 {2 A' X3 h - protocol_cdev = cdev_alloc();
0 N; @" T9 E e& e( g - if(protocol_cdev == NULL)
: {3 v# O+ N- S+ p4 ~) m - {
. S* G$ Z v' k) C3 l - printk(KERN_EMERG "Cannot alloc cdev\n");
6 M) W, }* ^8 |9 D, K7 w$ @- l - return 0;
6 T4 f& i9 c/ c% [ - }1 D, `/ H7 x7 k* L: T
- //初始化cdev
7 K2 j. s- B/ r8 _7 l - cdev_init(protocol_cdev,&protocol_fops);6 E" s0 |7 q- T5 a, F
- protocol_cdev->owner=THIS_MODULE;
# G! I. }: T2 G' G# S - //注册cdev
$ j! E$ c8 Z5 n: J0 c - cdev_add(protocol_cdev, protocol_dev_no, 1);
, C+ y* t3 @. n' S. R/ C6 w# `; c - //创建一个类2 C5 i, b4 Q" K2 t
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);; v4 k8 E) ^3 A# t2 Y" V
- //创建设备节点
9 Z1 y2 L) M9 | - device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);
1 J( `+ l8 U: V0 ^& P, W, q - ( z. B+ h8 r7 M& z* s0 X5 f
- 2 d Q/ o+ j! z' l3 S7 I+ e1 g
- //申请链式循环队列作为缓冲区DSP数据帧的缓冲区
( _$ I) z+ m3 S: \0 {+ N0 e4 a" N - k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区1 C1 U0 x+ r a
- ( N( d# D' A7 q0 z$ k( ]; [* T Y9 ?
- //映射ARM的核间通讯寄存器: f+ L8 u" t5 O8 ~4 x5 n5 V5 i
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
! w# [) }$ U" [- R# e - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);3 q0 b- |' V: E1 C
- //将物理地址映射到内核空间
1 y/ b( O6 O4 W: \) [0 V T - mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);# \: Y/ u7 c/ u6 N* ^; |& \
- //共享内存初始化4 C. w& Y4 w% k; p k; }
- SHM_ARM_Init((unsigned char *)mem_base);1 ^5 g* G/ j' c }- [
- /*申请中断*/: O: w4 L/ g" h
) w. }, C* r- T. Q5 }0 S/ J- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);! _ F& h; y+ v. ], T8 P
- if(result != 0)
# h) R% M% ^8 W. E$ K' Z) O - {
. J; H4 g" M. C! @. |& I" _ - if(result == -EINVAL)
& R- K6 z( V* H - {& r* \" [* b4 U. [( g: p) n& G0 E
- printk(KERN_ALERT "irq request err:-EINVAL\n");
: D3 `' ?1 V1 [8 R - } h% o* Q; [# b# U8 {
- else if(result == -EBUSY)
3 u" _: b& w. e$ z$ I/ D - {
U1 {* h# q; I, u - printk(KERN_ALERT "irq request err:--EBUSY\n"); v/ V+ _ Q5 g
- }
( ~( N. K# o; R) n; E2 c2 b9 \ - else$ R0 C; B, F+ w5 [+ @& L% k
- {7 |5 i6 n. d' x
- printk(KERN_ALERT "irq request err: unknown\n");
* X9 d, Y6 D8 }7 S* W3 O - }
/ C2 U' z/ _, ~7 d - return result;
# k" I/ |8 E& f; H ?, C - }
6 F$ Z* N0 e% u; W1 | - return 0;; F3 G2 Y1 X3 v
- }% `1 f. @ ~ |- F, W
- 8 [; H4 T: q+ B3 X
- /*设备驱动模块卸载函数*/' T& Q& [* Z: }% W5 c$ Q$ F& v
- void __exit protocol_exit(void) W2 W/ x1 d/ p' E7 G7 o
- {) {3 q3 @2 B* r
- /*释放中断*/3 G7 F: C( ?7 k" d( h
- free_irq(IRQ_DA8XX_CHIPINT0, NULL);
( L9 i) n& h& v- Y. g: G - //释放帧缓冲的内存: V; @* b \. U( u9 Y P' K9 l
- k_linkQueue_release(&queue);
/ m% v6 b" w+ h3 } - //释放寄存器映射0 ] V: G2 ]( O
- iounmap(R_CHIPSIG);
% N+ R/ o7 `2 q. h2 Y/ G, C5 F, Y - iounmap(R_CHIPSIG_CLR);
9 ?! I: h) j. P# h1 A0 W - cdev_del(protocol_cdev); //删除cdev/ x5 N5 ^" q1 P( [
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号
0 l3 d c- u& ~' b" K3 s - device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
. Z* t8 ?. a( r K6 g1 G" w$ w - class_destroy(protocol_class); //销毁设备类
3 n. J/ J- S# V/ A# Y6 D' A2 P* X7 d. I - printk(KERN_ALERT "exit success\n");) `5 O/ V d U
9 X. p: t d$ t/ D9 J9 @- }
. @2 h5 g5 z( H- \; y+ }* r6 } - //驱动其他部分省略
复制代码 * Y! ?. u" q: D- l/ x
' I8 L1 n( N, { M/ Z# V |