本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑 1 P$ z7 S5 C) ?+ ~
- ^' Y$ P5 ]# 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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略
, m2 V! |( c5 N1 l
" K+ J' U% V5 F2 `) u* v5 {9 ~- //引入其他模块函数和变量! [! C1 Q8 l1 N: t
- extern Ping_Pong_Buffer res_buff;
0 o6 V2 A6 w1 \/ ]8 d- f d - 2 Z4 \7 g) A2 v7 P+ ?
- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列
5 {6 x% ^3 q4 e, J$ S6 L - extern void k_linkQueue_release(linkQueue *queue);//释放链队列& N9 d' U* K0 c+ O! Y6 K* J0 P
- extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据4 @& y1 l. H: x7 }) j* I9 D
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据8 R3 n9 b- C8 g
- 9 B( i, y. l: w* l( Z
- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化
3 q. p7 }" P# t3 U3 P% f - . B- H, Q( Y/ n* J5 I4 j& i
- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1: _% E* J6 Q- w; K
- //设置主从设备号
5 [, j& i: b( r. c0 o/ K8 M: R - #define PROTOCOL_MAJOR 1" U D0 R; K" ~8 p0 P8 p
- #define PROTOCOL_MINOR 0
* u, d* c, `0 c3 |
3 p e6 e7 h" o$ x: X
% H' G+ T* g8 H& V+ \6 z J- 6 T, W8 q4 n2 o' E6 A
- //定义设备驱动的名字或设备节点的名字
7 A5 Y" o9 K1 ~% z1 A: V - #define DEVICE_NAME "protocol_driver"
4 r$ Z5 d; p# V" t/ e( `+ H- Y
, L* S! @6 q0 W
G$ |+ W7 d6 L# L- //定义全局的循环队列作为数据缓冲区
% x6 o1 S8 e8 B" A- a! D- Z - k_linkQueue queue;& M5 t0 y7 P1 R! \8 p) }( ], @- t
- : `! F T m" W
- //寄存器地址映射全局变量) y% ~ q( I! q! R. _: @2 U9 Y
- unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器# g* D% c( f. _9 w
- unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器
: [* Z8 R3 X7 Z4 Y" O
9 z, c# `) J* G8 \- e$ S% l7 G4 s- //物理内存映射全局变量
3 Y- ?! G1 u9 M U0 A9 c; ?; Y/ | - volatile void *mem_base = NULL;& W1 C: |) O. ~+ q; W* \
- volatile unsigned char *cur_buf_ptr = NULL;5 ?' u/ W8 P& X5 G) A) Q! Z( p
- volatile unsigned char *data_ready_ptr = NULL;
) Q' D1 d* ?; k6 A D! j - 2 t: @" M: L: A( Z D( _
: I$ G3 w5 b1 l* S9 t1 [- & d; q/ t% U9 b3 }- ?6 D7 Z
- //定义读数据等待队列头,IO阻塞
D, R# O- y& w2 z) X; a7 j - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);
" D/ i6 S9 j) y4 Y, \+ p! Q; v
; p1 n6 h! u7 G2 v ^- //定义原子变量
1 T% z \" G. q - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备! V7 N! ?, L% D+ f; g% S
$ g* b% j. d" w& z3 O/ ^- ) K3 U; @3 X. z1 q9 m
- //定义设备类1 n0 _5 R7 P5 b" h1 N: Y
- static struct class *protocol_class;
9 v7 `! e8 p/ H# r1 K* m - struct cdev *protocol_cdev;+ y: m# w& q1 }1 L* k1 ]; b
- dev_t protocol_dev_no; e+ k7 A9 o( Q( w" J
3 Y& v9 f' a) X- /*定义tasklet和声明底半部函数并关联*/
i9 D/ H! F$ U3 ~ - void read_data_tasklet(unsigned long);+ V6 I; x8 I% g5 t0 @( d
- 3 G# R5 w, ~1 Q4 E
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);7 Y2 Z9 z( S4 e, ~4 _, O
- //将CHIPINT0_tasklet与read_data绑定,传入参数0
1 V& T( p. B/ Y1 V
6 ]8 m/ ?1 M1 _- /*中断处理底半部, 拷贝内存*/
' b) o+ f& [1 }# r - void read_data(unsigned long a)* E$ r/ d: [7 b
- {
) N/ O% r L6 v - if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1" Q9 S1 ~$ m# K6 E0 ^8 [2 j3 U
- {
* d4 c7 Z' D' } N/ v4 l) X - read_quest = 0;
% Y" i! T9 N# I' J: U - wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
% b! @7 ^0 W( Q - }
$ E$ q# [ p- @' Q# E( y
7 N+ C+ u; L9 U0 p( j- g- }7 Z1 m9 U8 L2 P e
- 2 ^1 A" ~4 m! T* x$ M/ F
- /*中断处理顶半部*/
2 \' X: [8 L! \3 J - irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)
5 t: X/ `3 O. ], i$ H* U - {
9 v/ F- M& E; v - //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
8 H2 I5 D+ X# a1 o - volatile Buffer_Type *next_read;
% d- Z- n0 Z4 m v* [% V! d - //如果DSP数据已经ready) [7 H8 ]' N+ f& [+ {) q& l: k5 V
- if(*(res_buff.cur_buffer->data_ready) == 1)
' ?7 Q, o" A' E+ l1 p - {
" L3 _; o" H9 k7 W7 ~( h/ q( C - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer
# U1 H# g; j8 j) X" F* A - {$ [2 t4 t M7 y6 \1 K0 J3 y
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer
7 i/ T5 j. N. C: {- _ - //printk(KERN_ALERT"read ping\n");* c1 m; W& @/ g6 g' D& h
- }3 y/ d5 t8 A! l# H
- else
9 G. _0 l b& u( _2 ?- i - {
6 U1 O6 x, w& w: P$ V/ u8 y - next_read = &res_buff.ping_buffer;//下一次中断读ping buffer! Q! ?" q! I: K. ~9 m# u4 l
- //printk(KERN_ALERT"read pong\n");) k( J7 G" A7 y+ c/ p
- }
4 U( N$ F$ X# Q8 o8 c. x - *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer* l5 |4 x: s% \ V. m9 e7 M6 m
- //将数据插入链队列
% B% I; K s3 u' @( p4 b2 | - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);, A5 c4 x+ `" v1 e0 z6 f9 u
- //标识位都重置- D0 i3 L$ D0 f( y. D; p6 o
- *(res_buff.cur_buffer->data_ready) = 0;
2 X6 l+ P& U; z/ @; Y! v - *(res_buff.cur_buffer->data_size) = 0;
1 b% Q! \( |: u- U; @' } - res_buff.cur_buffer = next_read;
6 z g+ z, v! ]8 A1 Y - }
+ n3 Y% m2 w. N% U/ ]4 { - //清楚中断标识
" F$ ~" S- {5 e! K1 X V - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status* i" ~+ h4 a4 }0 Y
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部
4 ?( }5 L. U# A2 V8 j5 K$ J: c - 6 \+ k1 l5 z ?. u" E
- ! P Y$ n0 o8 G/ R
- return IRQ_HANDLED;/ u9 J- h, {" c8 ?
7 I$ J3 y% \7 j1 [8 p+ O- }9 c! O! {: l" g& d
- 1 n. ?$ n$ j$ Y- N* a% R# m3 D5 @& [
- //文件打开函数
! L* c! _+ }/ g4 _' a# b; D- k& B - static int protocol_open(struct inode *inode, struct file *file)
, _4 @1 v2 }% ?+ D - {
7 J! H# g I& A: k4 q5 T9 o - int result = 0;4 {( p/ |7 N& O( d- ] _5 k" _
- if(!atomic_dec_and_test(&dev_available))
: C8 E: d& t3 G1 h" | - {
, r" y# r) v7 V - atomic_inc(&dev_available);
: D* M% |. p) O - return -EBUSY;//设备已经被打开
0 C7 Q; E3 T! U - }) E! p' m% V/ T# `
- printk (KERN_ALERT "\nprotrol driver open\n");1 d3 k# z: i+ u- R
- return 0;
9 s2 C) |* h# Q! g0 I/ p7 k - }& W% S# z* ]( @( T9 t
" H$ K7 k* {1 q( u- //文件释放函数
7 a! k1 _; u* G$ r9 e - static int protocol_release(struct inode *inode, struct file *filp)
; n# m+ |7 P; I* m4 O! j4 n5 T$ |1 R9 l - {9 z+ ? z% _' b9 _
- atomic_inc(&dev_available);//释放设备,原子变量加1
) |" w0 c* d+ v, Q; C - printk (KERN_ALERT "device released\n");; [+ R4 G- M- @& z- f& U
- return 0;
1 @8 h! x/ ~" K, l* c9 \- g$ G, z - }
% n* Q& n9 L5 Y - ' m# x% [1 N2 O6 D! x, S, ~
- //文件读函数, k& a% K+ |% G# o# D: U9 e" ^
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)
) \7 N& I0 l, n. R6 T& N0 j - {
8 x$ ~0 f$ i9 S0 z( | - int ret = 0;6 A3 U' i. ]# j: `# ~3 k( s! I
- //定义等待队列5 p1 I7 z5 Y- _- I5 ^( N: c
- DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列
% @+ X8 s( P' _' Z# t, @ - add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列0 r% G, }) Z# t6 Z
- if(queue.remainNumber == queue.blockNumber)//当前buffer没数据# z2 G' r: w" n% U. U
- {
0 g; P$ G: Z5 O4 x2 l( Q3 P - //printk(KERN_ALERT"\nbuffer no data\n");
9 Z9 R& y) m/ \4 T, O# w$ [ - //如果是非阻塞方式读取,则直接跳出
$ s6 M# q$ r6 A( L$ ~1 u - if(filp->f_flags & O_NONBLOCK), [7 V! L. }* {$ k E/ F" E
- {2 P' }3 N! t/ z1 j
- ret = -EAGAIN;
$ _5 s* f0 P Q. \* ~! H; v/ p - goto out;: y1 w1 M# v& P; N. Q3 |: T
- }. p. {9 m8 ^0 i) l' A
- //阻塞当前进程,放弃cpu资源% E; K+ \( `2 p3 O
- read_quest = 1;
7 e6 h( W0 F9 c/ F M* u! c8 s - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠* E! A: o. G) c. s7 `% U
- schedule();//调度其他进程运行
8 n* b* z1 U- k& _7 N* e. G8 r) H - if(signal_pending(current))
6 @# g- \6 q6 `) ^9 Y - {; a$ P1 e6 C* H" H
- //如果是因为信号被唤醒,则返回到系统调用之前的地方3 C, ~2 Z0 k# P, S" {8 l* K
- ret = -ERESTARTSYS;; o: U: Y3 y8 u4 N$ M2 m
- goto out;
- c y3 J D, \6 H7 O. _ - }' c5 }8 X% T- b) C* o+ b2 ]
- }% o- w# a L" K! \- U( |! Y p0 i
- //将数据拷贝到用户空间
0 s6 T% p3 @& C0 }4 l* E! @ - ret = k_linkQueue_getData(&queue, dst);5 m/ O0 a' G8 v2 _/ Y" _, c7 V4 c
- if(ret == 0)
% N1 |% H0 x, U2 a+ u - {( y) u5 j/ N! l, }8 K7 Q
- //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
* L, s- e( b8 e" [ - }
- A0 D) [& L- Z$ \- A4 ]; Z - out:* N: \3 a8 j& R
- remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列; b/ G- y' r D% z
- set_current_state(TASK_RUNNING);//设置当前进程为运行状态
3 y/ B) P; T7 ?6 B( N x - return ret;+ \; Q8 `, x% \$ a
- }2 @& m$ ?1 n. q& O$ a+ i: W
- & N2 d4 E5 R/ x. w% ~
2 }! M; x& ]$ u. ^1 f' f4 d- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)9 W1 N# {+ [. z, w0 j' D
- {( D: E$ c$ I3 L8 L( T
- return 0;
" E- N3 O' s! U% H0 V2 ^: L$ w E0 x$ K - }
6 S5 B$ o- h U% s - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行2 l' h) F1 v% D
- open()、release()、ioctl()协同调用时被调用*/
" e3 y9 P V/ {7 _! v - static const struct file_operations protocol_fops =
( G9 y! }7 a% w. h - {
8 ~2 |$ K; F* w2 o! F8 t: w7 { - .owner = THIS_MODULE,
0 T; y9 w) [5 @, {6 D" J3 ~% A - .open = protocol_open,% D6 h4 y$ j$ v0 K7 ?
- .release = protocol_release,( ?& ?2 `2 C0 {& \) T8 x \/ u
- .read = protocol_read, Z5 v4 O( O& M' L8 l) ?4 m
- // .write = protocol_write,
* b4 D: c9 s+ n* r/ m. }8 L) ~ - .unlocked_ioctl=protocol_ioctl,# \& Q( m' k4 S, {6 t( s0 t" v
- };
4 ~5 J1 l4 w( E/ n% H4 O- T/ i
. u* e8 E8 |7 P2 z4 |: ?- /*设备驱动模块加载函数*/
# A; Q) q9 p6 [: L2 l - int __init protocol_init(void)
4 U7 `8 J' V0 t: l - {
* p" K `7 N; U% z1 u9 R5 k - int ret = 0;
( j5 V6 Q% C# Y1 u' `: V, k - int result = 0;& e6 V" o9 h8 k8 X5 R8 d
- //申请注册设备号(动态)
% P; d1 K! ?: t" ?! K$ P" ^9 L- s - ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); 9 i9 K+ n/ Z" ^- A: j: O
- if(ret < 0)
9 R) D" }, Y7 B/ e7 G - {
2 N3 y* G8 G/ S0 x+ o/ Q% U - printk(KERN_EMERG "alloc_chrdev_region failed\n");2 `" y% J G) B' ^; H: W
- return 0;
N' p; E6 C9 c8 X - }
' q2 `0 H% _6 w: H - //分配cdev
. {) C/ k% ^" N& `' X% Q. @5 V - protocol_cdev = cdev_alloc();
2 P/ L2 G. m$ }8 ~& e. z) H - if(protocol_cdev == NULL)# z$ P' M/ ^9 B( `- [
- {
e7 d) N+ U' U4 v! I4 }( { i" t - printk(KERN_EMERG "Cannot alloc cdev\n");
* Z1 ~6 \# u2 m. S1 Q - return 0;) y5 x/ s: L1 G2 \% p4 m# m
- }7 x; L8 v% F- x' k
- //初始化cdev
0 y- Q9 V! N7 l. I8 b - cdev_init(protocol_cdev,&protocol_fops);0 K1 i# D. e3 x4 [8 ^5 K3 S/ Y4 _
- protocol_cdev->owner=THIS_MODULE;6 j4 I$ G4 Y- f
- //注册cdev
' r: v. h5 v* b2 O9 r - cdev_add(protocol_cdev, protocol_dev_no, 1); 2 P8 L% `5 \$ j5 C( z
- //创建一个类! ^. k/ o) i* A8 C8 Q
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);: P; p8 d" `& q1 w( G/ J. D
- //创建设备节点: t4 E2 x( o8 b* F/ G
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME); P( f+ u, D( x& V) K6 x# M V
- 2 Z3 e' X% H( X2 H! y/ B7 B
-
' l+ {; o2 W, ^- i: T: M" s& c - //申请链式循环队列作为缓冲区DSP数据帧的缓冲区3 k5 R8 T6 E, ~& s1 \8 J
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区3 u, p' k) s z. w4 n
9 u9 b7 X$ @1 K6 {! n- //映射ARM的核间通讯寄存器4 y+ a9 G+ K8 t: p8 K8 ^
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);3 [% z4 y8 `4 t4 x8 R
- R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);0 Y. r% I, h1 H. C
- //将物理地址映射到内核空间
5 {" e7 k, Y0 y0 h4 o% m - mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);- ^8 q/ a* j! W6 }% ]
- //共享内存初始化% L' K5 ]! d* f( p* ?+ Z
- SHM_ARM_Init((unsigned char *)mem_base);
4 o; V5 A6 w4 i" }# _& h - /*申请中断*/
& } t6 x, ?) W: F/ c [9 Y6 X" h
/ {) j4 o1 h7 U! v, U- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);$ }; D5 `0 R, N! @+ O; J
- if(result != 0)
5 Y; p2 q& K# l: L - {
* \ ~; ?4 R& B. ~ g4 S5 d - if(result == -EINVAL)1 B8 }+ i; r8 ]1 n( \
- {
# f& G2 \/ o8 m# ]. p# n - printk(KERN_ALERT "irq request err:-EINVAL\n");
9 U( Z3 }1 p+ j, |3 w - }
4 _. C9 R# R% r - else if(result == -EBUSY)8 B+ W, X( e- q2 o6 y
- {* J& \& J! G; k
- printk(KERN_ALERT "irq request err:--EBUSY\n");+ v+ R9 o3 c6 W: t7 T
- } Y, K6 ^$ u( P; e
- else
3 f# U3 b6 {! } - {8 n; O$ O9 j1 ?7 Q, N
- printk(KERN_ALERT "irq request err: unknown\n");
+ r+ c5 T% {8 J: n/ L - }
# ~. F2 ]; Q4 i8 M* a! I! E - return result;# L) N9 q7 \& X: q; _% P! o0 C+ Y
- }
% h" B5 O; v/ r+ f! V5 z+ q - return 0;
& |! a' ?. o2 ]! k: j% z6 S - }; z5 I0 x3 m5 M4 n9 M, ?; U- d$ P
- . V5 W4 [7 K: ]; ?4 P1 t3 K1 D) S
- /*设备驱动模块卸载函数*/( x8 y9 I) [$ J0 g M. _8 |
- void __exit protocol_exit(void)2 }6 k, H0 O% z" P" P6 } K; F) T
- {' r! n N. T0 `- d, J; @( Q- e
- /*释放中断*/
: A; P5 c2 V& V! B) a - free_irq(IRQ_DA8XX_CHIPINT0, NULL); p; `& J7 W6 G+ k) m7 ?: f2 M b
- //释放帧缓冲的内存/ `* ?9 m% y7 ]" V0 N a
- k_linkQueue_release(&queue);* K, s/ B, d1 L6 L/ u
- //释放寄存器映射
8 q( S: d; Y3 i3 B- r - iounmap(R_CHIPSIG);7 j+ }" w4 G9 g4 p+ ~* {% Z
- iounmap(R_CHIPSIG_CLR);
2 v" `. E/ J# ~6 s' B e! ]' y* E - cdev_del(protocol_cdev); //删除cdev
) V9 z% ?, G$ v1 r% b - unregister_chrdev_region(protocol_dev_no, 1); //注销设备号, p8 f" G3 R$ B& ^' r
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点3 r N4 x& Z" A. ~, E) S' m; ~. ^1 Z
- class_destroy(protocol_class); //销毁设备类# S6 P3 |& X0 N. m7 T
- printk(KERN_ALERT "exit success\n");. c q6 }) p4 n* B$ k2 n# d; X1 ]
- - [% p- a/ v: z( D
- }0 E4 Q1 _, f6 K" b* R! k
- //驱动其他部分省略
复制代码 Z; Z! B+ O7 |
- b$ V. G6 K X: Q |