本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑 & F: O3 z. F# e2 z+ G& R
( \$ T5 Q w& ~
项目要求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 |! i; H$ V% ]& [8 l' g
1 H0 m3 Q+ Y6 A5 v- //引入其他模块函数和变量1 d; K% u$ Y2 E# F2 r- w9 Q. J( ]8 v
- extern Ping_Pong_Buffer res_buff;9 y) A ~! x7 g" P" q: D4 ?& J. k
Y- F- y) l/ I- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列
: r4 ?9 A4 C7 P! C1 L, Z - extern void k_linkQueue_release(linkQueue *queue);//释放链队列1 C3 y0 @- U/ f0 S& n1 A' p" u7 V
- extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据# c8 e0 C# x5 G, ]* `! U
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据
; T& M. Y+ P/ n* ]3 K N) g - ) O" h3 k) P( C4 U1 {5 I2 g& ]7 k
- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化- B& \6 Q5 A1 q. `7 b( g
+ z0 y/ @ D! `8 t$ U/ x, V- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1
, y! M4 B- w. l- W4 V! q k6 q% I( G - //设置主从设备号7 p/ T, U- m# o: O" C% }
- #define PROTOCOL_MAJOR 1% ^. N5 W% F) a3 k& R N# C2 @* y
- #define PROTOCOL_MINOR 0
6 I4 ]% z9 @ C# [/ d4 i. Q
. ~/ y5 U7 S! C- ! @- z5 y. b1 k( v& f
- " C( X5 P9 J U5 X
- //定义设备驱动的名字或设备节点的名字 V* j: H8 I& C- V" Q8 }
- #define DEVICE_NAME "protocol_driver"
$ |8 d" @1 V; c q
! s- C6 [+ Y5 p- f' B- c- {7 H
! A/ t0 X D! }$ x& n" Q" s- //定义全局的循环队列作为数据缓冲区
- {- [1 v/ H! A; V8 i" f( |' a - k_linkQueue queue;
; V6 G n" R5 d
5 `- O! H: R' V- s8 U8 ^- //寄存器地址映射全局变量
t' t& H) ]% a! y+ C% r; b3 z0 Q, r - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器
9 b: }8 o) C/ ?) p1 n8 k& Q f - unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器
- X. m- n# |. c: o6 S* C) K - ; n' b9 ?; I1 |& n K7 P7 S
- //物理内存映射全局变量
4 L* A# t' h8 P* D3 T& _ - volatile void *mem_base = NULL;! ?% s5 o5 Z* J1 [9 e: s( O/ ^
- volatile unsigned char *cur_buf_ptr = NULL;
" {% H2 E5 Y# e+ Z; |) ?7 v7 p - volatile unsigned char *data_ready_ptr = NULL;' I) l3 E9 E3 I" b' H6 y( m# j
- ; f/ e7 b$ H; v, x+ z3 S4 d6 Z) w
- : O5 N# t% k; l9 w+ X3 L( v! J
7 V7 [& E$ L' D, r/ J- //定义读数据等待队列头,IO阻塞
0 ^" K& S$ V$ c: m( g; ^' d( m - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);
- j3 L9 R U& J. y5 S: c - " ^* N2 N' \& U
- //定义原子变量
6 z6 b9 _! m3 A# v7 g$ | - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备
% v7 L& G4 [# l0 [( o+ O4 h% f: t3 _( Y
$ k/ {8 z. C1 @+ b' _- 5 W* G- }7 s. i% V6 s N9 L* j
- //定义设备类
9 I: ^* p- g! n. o# u - static struct class *protocol_class;! ]' i/ L9 E5 U3 y" L- S
- struct cdev *protocol_cdev;8 X5 `" n5 p& ^, ?3 S5 H+ C$ q: I; o
- dev_t protocol_dev_no;- \% y0 Q! @ g. t$ S X
) D3 c, I* X( f( o9 g- /*定义tasklet和声明底半部函数并关联*/6 ?# [; C5 L/ Q' c1 q
- void read_data_tasklet(unsigned long);; n( G, b) o! i4 u
- 7 T8 G x4 t' Y# Z7 }
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);1 `; \& l, z. h& I; J8 j$ o. s
- //将CHIPINT0_tasklet与read_data绑定,传入参数0 u T9 X0 _* z+ T. J2 i3 {
- $ M( H) A5 N! {( o! U
- /*中断处理底半部, 拷贝内存*// G ^0 ~- d& L2 u: b
- void read_data(unsigned long a)
+ F0 x- Q E1 x# ~) ] - {
- G% r) E2 M4 r) B) ]9 G - if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1( C, ]5 ^2 f. j6 z8 ^; z
- {
8 Y, c- s8 L/ d; r$ Q, o - read_quest = 0;$ U+ f9 }' l- X( Q8 N2 f7 S
- wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
; ?( P; Q7 s8 h. h' c - }' x) X6 A& ]5 f" p- k$ h( C
- ! A2 F! `( v1 R) m$ Q; h# J
- }* `" X7 [/ w: j7 J! ~
q4 O& J* h. W W& B% t" W- /*中断处理顶半部*/: s# w$ q+ L2 K) M8 Q; {
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)9 v& l+ p* G3 Q2 |: _0 z7 R' y
- {
- u& f+ \ w$ ?) T* l- ?8 V - //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
3 }0 P3 Y, R* i( w - volatile Buffer_Type *next_read;
- x3 F- q5 _' V, o3 I# g" m - //如果DSP数据已经ready
9 g+ D. z) S8 }. k - if(*(res_buff.cur_buffer->data_ready) == 1)6 l& T8 @/ N7 Y2 F
- { W9 B: G2 {5 w
- if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer8 U" R* D# m+ o( ?
- {
5 S/ v9 ~( t6 h; c' M - next_read = &res_buff.pong_buffer;//下一次中断读pong buffer
9 H* H3 t/ H' @' Z - //printk(KERN_ALERT"read ping\n");4 ^9 r+ Q6 o5 K t% ^
- }
' {9 t! x/ v; c1 z, p5 a - else" H9 j& M* I: q: y& L
- {
/ t$ k c! `0 [: {4 P - next_read = &res_buff.ping_buffer;//下一次中断读ping buffer6 k; X) j3 m* o a( D
- //printk(KERN_ALERT"read pong\n");8 I5 v, Z4 e2 Z. B8 t Z3 Y
- }6 n% f/ u% h# H0 s9 j# `. b
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer
$ J" d/ H( M0 s+ R; A, v - //将数据插入链队列
6 z- D; v; [0 u - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);7 r" F6 e6 a( I4 k# }. M2 U% a) L
- //标识位都重置0 Q, u0 J- f! ?; L
- *(res_buff.cur_buffer->data_ready) = 0;
, _6 z0 ?, P( J" r0 a, t - *(res_buff.cur_buffer->data_size) = 0;7 U$ e9 e1 P) ~- F' L
- res_buff.cur_buffer = next_read;
/ f1 E9 t4 U! x3 `5 `( u - }
+ V6 A: u9 ^3 F0 l3 s% k! o; L - //清楚中断标识# ]# k5 z% `; h
- *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status6 W& ^- w+ {+ {/ D, E
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部
" S' T6 o h/ G6 i
/ ]& o% j1 V# U" R. ^% ]- 6 c- J+ _1 D3 x o: }* w$ q. c. J
- return IRQ_HANDLED;
- H* q' S' v2 m6 }! K, j - 6 z6 [/ z; J' V3 u
- }# _9 [3 ]4 o2 k3 }0 |# p
6 c1 q! Y! }& s" Z6 c7 T- //文件打开函数( r: I/ p- g! _
- static int protocol_open(struct inode *inode, struct file *file)
, J. t j; _. u, a5 E4 b - {7 b0 [+ D3 _6 N% h* X2 x& ~7 c
- int result = 0;
u$ e+ x7 S) {& F, b9 L3 z - if(!atomic_dec_and_test(&dev_available))
0 G* X$ o' ?% R - {
6 L5 ?. W0 H( |4 J8 Q' Z& e3 b1 q- p - atomic_inc(&dev_available);! M1 c7 m( m7 e* r
- return -EBUSY;//设备已经被打开
8 e5 C( L) K: F6 X! L - }
9 M; }4 B3 a$ B2 x - printk (KERN_ALERT "\nprotrol driver open\n");
. D' r% E# o+ |) E; y2 P - return 0;
! \2 D1 S' T: T - }
* P5 v* q0 a" o7 ~
$ t& H, g5 r; l- l9 i0 R- //文件释放函数4 _5 }6 b( M! q
- static int protocol_release(struct inode *inode, struct file *filp)
, o9 H7 R; T6 j - {
( s* D% N O( S9 y! e' q% Z5 t1 T - atomic_inc(&dev_available);//释放设备,原子变量加1! k/ ?9 K/ F0 Y* S0 b6 O7 j2 ^
- printk (KERN_ALERT "device released\n");
4 d; @) K% p; U) k' x - return 0;7 z5 i% W6 j v& s: L* n
- }4 \+ W; \" b) _ I
- 3 Z& U8 b R' r4 s2 [+ t$ S$ n- \
- //文件读函数
) `2 Q. E5 P& D! g. _6 u - static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)
. ~8 P6 v6 W9 J2 V" u5 M- q - {7 c# M9 P0 L3 I* M" ~3 p
- int ret = 0;# ]0 A0 A3 l" h9 ~2 G j0 i
- //定义等待队列. g7 i& ~% U' p4 p" S. P# W
- DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列
* e0 N! h8 P1 D5 C3 H - add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
0 i$ J4 t4 k' E# x - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据% n8 J; y5 T% O$ M* d
- { m: N W! Y g" j* D
- //printk(KERN_ALERT"\nbuffer no data\n");
1 R2 l- D* w+ X; t+ e - //如果是非阻塞方式读取,则直接跳出) M) C3 P; K3 B& C r* B
- if(filp->f_flags & O_NONBLOCK)
) ?6 `- s5 w2 f* N# v4 \ - { Y2 W% V, M0 E9 u; K" @' S. ?& O7 G( [
- ret = -EAGAIN;, F+ s8 m2 b' w0 [ t' j. p
- goto out;
2 m% c0 a8 \$ h7 c$ h% n - }
( r4 E/ t; `0 o2 S/ q: j M6 e - //阻塞当前进程,放弃cpu资源7 q3 C8 M! {& }9 |
- read_quest = 1;- D; \, K! e4 C9 B6 c" z1 N1 _5 }2 M
- __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠1 i O, @# N$ c' H( v# R# u
- schedule();//调度其他进程运行
6 V2 Z# v9 M3 Q8 _- D - if(signal_pending(current))( _9 O; ^/ O7 j, \) j' a8 A3 r. L, L# z
- {
5 u V( k: s$ ~' l - //如果是因为信号被唤醒,则返回到系统调用之前的地方
4 P) g1 H) C) L - ret = -ERESTARTSYS;
6 S& D3 l6 N' w - goto out;
2 K3 u v& d* i- Q$ M- Z - }
$ l9 K, n) T! B e+ c6 f: a: ]9 X - }
& a9 K! S- b/ f - //将数据拷贝到用户空间: Y0 g1 ~ n4 A4 v
- ret = k_linkQueue_getData(&queue, dst);
* ]: I( ~9 B4 z9 O$ _% c - if(ret == 0)
/ T1 G0 C9 J4 I$ y - {! _2 }5 |. G' p' _7 ^- F
- //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
( _! s8 [3 |/ j0 v0 F; Q, \: _; Q- a - }: Q; s# E- b; p; \* s
- out:
% v2 `% Z2 a! a% _5 b& T* E* R - remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列* S) r% J/ T9 @; ? M" L% A2 _
- set_current_state(TASK_RUNNING);//设置当前进程为运行状态7 u4 o: x5 [/ b
- return ret;
( H* l0 l* G. d$ U6 A - }
' \; X I1 ?/ D3 X/ ?: V G - 5 N" @ U0 Z K; ?/ a' H+ ~
6 X! ], X( e1 ]6 ~. r/ J2 J7 Q o- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)& x5 a! s- I$ z: k
- {
7 ]" G6 Y/ E9 _# d5 F$ } - return 0;
( q( H5 N# g) @2 u, g - }
2 P4 `. z m0 R" X9 f - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行. t2 M# s& @% u: C- `
- open()、release()、ioctl()协同调用时被调用*/2 }0 ^# G* J+ k. M6 m
- static const struct file_operations protocol_fops =5 w$ u6 e# L2 L* i0 M# ], `
- {
& a9 b6 Z9 V/ J. O9 F0 r - .owner = THIS_MODULE,; Z/ `& C1 v! j+ S+ U! S7 }8 O$ I
- .open = protocol_open,+ j+ `2 N2 p' ^: n. Q4 H
- .release = protocol_release,
1 Q) t% {$ z4 s' `5 O; P - .read = protocol_read,% U, T+ v T$ [! E- ?
- // .write = protocol_write,
% w9 o; Y7 D7 @6 V- X# l - .unlocked_ioctl=protocol_ioctl,
) f7 \8 p# G. `3 ?. c7 b - };
Y. o2 E8 d( o5 h. Z5 K
" {; L7 F Z% i& y# s" O6 G& m- /*设备驱动模块加载函数*/
. z) r; i8 K. n# ` - int __init protocol_init(void)
# ]' t( ^& J/ } ]" _% z1 z - {. X+ r3 l, ~1 q) W, h/ e3 V
- int ret = 0;
; t2 E+ _+ p' T' H1 R3 s* [ - int result = 0;
5 s% v3 y* d" ]+ D - //申请注册设备号(动态)+ l- Y1 q" I% \, ~9 v* h D" r
- ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); ! t* E' L9 d4 u. d
- if(ret < 0)
2 a, C9 B$ o! a5 \ W* _! [ - {
% d& A( N4 X# Z% ], o: ?; X/ C: L - printk(KERN_EMERG "alloc_chrdev_region failed\n");
4 O1 Y6 x5 _- M/ N+ o! @ - return 0;' A1 O- a. o0 J
- }) q* i1 ?0 `$ d2 s' v, \
- //分配cdev
" R7 C5 B L& [9 c O( h' G( V - protocol_cdev = cdev_alloc();' p% Z$ O0 Y/ r& S1 D
- if(protocol_cdev == NULL)
+ x+ H& M0 ~ E' V. Z% A# e7 @8 f - {
* B3 }# D* p0 S G - printk(KERN_EMERG "Cannot alloc cdev\n");3 j( j) c8 b9 I D0 Q# O
- return 0;1 d, Q2 X1 l1 {9 l, W
- }8 O- {' D+ c+ Q4 q: r9 c
- //初始化cdev$ ?. v$ ~4 G+ F4 Y
- cdev_init(protocol_cdev,&protocol_fops);4 z/ }7 T* E1 t6 ^
- protocol_cdev->owner=THIS_MODULE;
8 X% O, ]) Y9 v. T - //注册cdev+ s. u0 y+ h2 G% c. |
- cdev_add(protocol_cdev, protocol_dev_no, 1);
$ y S& k5 b/ t, Z - //创建一个类% j$ v O* G% A
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);( d7 y6 C2 Q) i0 b/ {) y5 I
- //创建设备节点 C6 y2 i+ w8 D' f1 I( I! c. v+ r0 O
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);
4 E' z% J3 t5 _/ {/ S5 O -
: i+ T6 {" z0 A0 N3 y9 U- F - * L0 v# x8 T# } B- q( L' P
- //申请链式循环队列作为缓冲区DSP数据帧的缓冲区1 t1 r5 J3 Z6 R1 S: \
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区! l- B8 ]( q$ J# M3 Y) I9 Q6 H
) v, @! V0 Z1 O( _) w4 {- //映射ARM的核间通讯寄存器
) D8 [" n q. f) ^; }9 F - R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
8 g! f" @* A: t4 e, ] - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);5 c1 }- o% X# B/ Y9 ]( a
- //将物理地址映射到内核空间( v# ?, L# e3 k4 r7 k% e- e1 h
- mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);& @4 j, k7 [8 l# f% D/ g3 q
- //共享内存初始化
: y/ G( T/ y& H - SHM_ARM_Init((unsigned char *)mem_base);5 E, L0 D" J" u, s# ]
- /*申请中断*/8 g; M1 h. G/ A6 M; e9 Y+ }* A
- : S/ w0 ^2 L( H+ q/ W# I6 o2 `
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);( l- R; P! q, V2 V# }$ m' h$ x
- if(result != 0)
# d+ E/ c& S0 R: e* [% k - { q5 H4 K* {* W! x# M. g
- if(result == -EINVAL)
3 R1 f+ k5 Q$ Z, V! B! b - {+ o f; H! ]" B/ w( u
- printk(KERN_ALERT "irq request err:-EINVAL\n");
% }- \- c8 b3 u2 i - }
, k0 _$ J% _3 D/ p* V/ e3 h - else if(result == -EBUSY)2 H: j+ h8 O7 z% N
- {
! k# |/ ^3 Z, Q( W7 s% G6 X7 A/ k - printk(KERN_ALERT "irq request err:--EBUSY\n");
. P3 M+ c, m* M# Y. W3 g - }9 y7 k3 g, v. y9 D H$ L* m
- else
, V) A* ], ^" D9 b" Q7 F" ] - {5 Z1 i+ a$ N' a, d5 p3 u
- printk(KERN_ALERT "irq request err: unknown\n");
8 b0 K8 U* L! Y8 a - }
, Y6 ]1 S+ z6 C) { - return result;0 y0 n! l) R$ ~: N2 i. D$ i g
- }
. |- o. {, U! W1 [4 C - return 0;
9 s( l* M1 ~- _, P# A' F. [ - }
0 D7 u$ H1 i! I5 z/ g% a
& \" ?$ o8 o# J* D( w+ i2 T- /*设备驱动模块卸载函数*/% _+ Y' O* M5 S( K) X; O
- void __exit protocol_exit(void)
" P; E3 K4 ]9 j7 | - {( C! `* D2 v u, H: W, d
- /*释放中断*/
4 [ E' G9 i3 _; u' X3 T7 \$ X/ N - free_irq(IRQ_DA8XX_CHIPINT0, NULL);
* k1 }9 ?- R* F - //释放帧缓冲的内存
5 _4 H2 j( c7 G* P" Q2 z - k_linkQueue_release(&queue);
$ f7 w2 r6 L8 |5 I$ i/ L# W - //释放寄存器映射' w1 v; m8 _) M6 v+ \7 b) l
- iounmap(R_CHIPSIG);2 `1 M) q& b5 }! V8 f( R! ^
- iounmap(R_CHIPSIG_CLR);1 C" b8 Q: M4 T. Y8 O8 h
- cdev_del(protocol_cdev); //删除cdev; E, Y$ t3 @7 C6 ]! `! y
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号
' ?2 _* }2 p3 q# h7 ]6 `# S - device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
& b: _! _1 h6 H - class_destroy(protocol_class); //销毁设备类
4 _- \! T: p) c7 Z - printk(KERN_ALERT "exit success\n");# H$ E( X& R, D" g
- - K. T. c$ R8 e" \0 E: z. F
- }' ?1 {; a; ]0 P. `4 I
- //驱动其他部分省略
复制代码
- h4 m& Y' g* |; n8 U
. E% H7 c2 j) n2 |1 u0 P% ^0 r/ A |