本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑
: f0 Y0 n# j3 u
; _! h0 }. e3 y( h项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略
4 i _; Q7 l; D
# g* h7 l& R# T& n5 |- //引入其他模块函数和变量
) `1 U) {" L0 Y7 c* z# o/ m - extern Ping_Pong_Buffer res_buff;# q! z% T, f+ B) V
- " L4 L- t+ F5 a7 K0 f4 t, M4 ?
- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列
* m; y* H& A$ w, D. b4 I - extern void k_linkQueue_release(linkQueue *queue);//释放链队列2 J" Z2 |% Y. T0 p1 F. |7 `
- extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据
9 @* H1 T7 Q. E( v& b. g - extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据 t; o: d5 x3 B& J
- 6 x: v( T, L/ L, c
- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化0 C# ]; Y! O5 X) h6 Z" T% ?
! a `' ~: x1 z: \/ [- [9 z- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1! i& t" _0 a& g6 x
- //设置主从设备号
9 m6 |- v, `( _4 H - #define PROTOCOL_MAJOR 18 W7 H, f$ o1 o! d a9 {0 G! F/ K
- #define PROTOCOL_MINOR 0
: _3 z+ U c, l8 _( c8 Y - & \8 r8 H5 ~) d( E
- % z2 @" x, }: F9 L# T$ X
- ' ]* I0 E/ c0 C
- //定义设备驱动的名字或设备节点的名字
( C+ K+ B; t: o$ d% J - #define DEVICE_NAME "protocol_driver"
! r/ d5 R: ]" j. P7 p - % s1 g/ b1 c% L3 `- H* Z) M* }0 B% ~
' e! D5 L6 ?2 K, c1 q- //定义全局的循环队列作为数据缓冲区
4 z$ U; o9 j: M8 ~ - k_linkQueue queue;4 ^( H3 @$ Z: @4 z8 t9 H/ t; D
- w1 ~$ y7 P, S- //寄存器地址映射全局变量
# ^1 }1 W8 R! M - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器. N" X, C! `$ J4 r* _& v4 B
- unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器
4 j: l: E, |' [) n
( z, B. z! J: b# k* E- //物理内存映射全局变量, y# Q7 d* h+ i* h( U' y2 k3 n: _$ Q
- volatile void *mem_base = NULL;
' B( ~" S+ [0 f - volatile unsigned char *cur_buf_ptr = NULL;
9 P3 r; x: b2 ?1 z - volatile unsigned char *data_ready_ptr = NULL;
' c4 Q. y; |6 g s% g( D8 s+ l! j
9 |( S, q! o, j) t% m* e
$ D- e8 u/ q( y- + h7 u, E" M6 I/ F: ]2 m' m/ {
- //定义读数据等待队列头,IO阻塞* {. `; k7 r b |
- DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);+ \% t* S C3 Z6 K
$ Z; ^7 z6 a |- h! u% p- //定义原子变量$ N; E1 B# ~- d- R: T$ j% s4 b: w
- static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备/ ?3 p9 e6 {* e$ t% o2 [
- 3 A, }" W- M" j1 C- b
- 9 V$ ?9 K# t* N9 ?7 S4 s- s [4 i
- //定义设备类
1 a7 C6 F4 o" K* G1 j( O, o3 c1 p - static struct class *protocol_class;. A- W# _4 ~- h) c7 K/ O' |
- struct cdev *protocol_cdev;
8 H/ F% }' r$ E9 {/ b+ B4 L - dev_t protocol_dev_no;4 W# {; `1 O. Y. H
1 V" E1 E( X$ k- /*定义tasklet和声明底半部函数并关联*/
4 d% |$ c$ ^5 e: p# j9 l$ \ - void read_data_tasklet(unsigned long);
6 F! H4 _4 O5 N2 P+ d - ' ^6 B$ p) t. k4 x5 e! i' w
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
- V% k& S3 }3 n# Y7 m9 ^ - //将CHIPINT0_tasklet与read_data绑定,传入参数0
0 V) w Y9 r, Y4 ~
6 k+ f3 `) M* o; k' X, \$ j/ ?- /*中断处理底半部, 拷贝内存*/4 h5 g( v; {- ^4 ^
- void read_data(unsigned long a)2 x8 h6 \: D! w* t: H/ z
- {3 r% W e4 y4 M+ q5 ^$ m
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1
& v( j( j" a% |+ l5 n& ? - {
# K% e. K5 f' W; ^$ X3 _ - read_quest = 0;
3 L( s+ }) z* @% \7 m - wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
8 s8 ?8 Q( c+ |. ~' \ - }
2 E7 y" H# g7 ]) I8 S7 F- ^- d# I
8 i) \2 ?9 |8 k2 ^0 K: S- }5 X( z% l. h' K. Z
0 u# S; O' O( r) i7 q- /*中断处理顶半部*/
! e, e) Y! R7 K - irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)2 ]. D2 r1 u4 @) @
- {" D {( g+ t6 i, [$ p( K1 \
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
. ~0 t, C% @: C - volatile Buffer_Type *next_read;
0 r# g$ W6 Y3 ]# F4 E - //如果DSP数据已经ready) S0 e$ L. ]4 w' u* N
- if(*(res_buff.cur_buffer->data_ready) == 1)
1 G/ v6 U" r& v4 |! ?- p - {( V8 L& {8 _$ K, s
- if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer
; Q! @9 d! l" [% }4 X: w - {
# d& ^, W" i7 M* h; L! ?" _9 j - next_read = &res_buff.pong_buffer;//下一次中断读pong buffer' _4 o; d5 U C
- //printk(KERN_ALERT"read ping\n");
( s0 |1 q7 Y2 ?0 Y5 X x, g7 j - }" a5 ^1 {# ?7 F+ p( u( @( w6 h
- else9 N6 y" O, Z6 M" o2 s. Y
- {
1 ~+ ^" n. Z8 ^ - next_read = &res_buff.ping_buffer;//下一次中断读ping buffer$ s5 y* a& k% B
- //printk(KERN_ALERT"read pong\n");
2 K9 _; D: E& H3 q+ _' P* i - }* v! B7 y/ f! C) ~; F
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer
& a9 l- p& U# r: T# v - //将数据插入链队列$ d, p5 ^! |$ h! `2 X8 e$ {7 M
- k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);
* y& F6 p7 f8 l o2 A7 o9 O - //标识位都重置- d3 E% R: c5 c# R; E" g: i8 G
- *(res_buff.cur_buffer->data_ready) = 0;! ?3 P' Z1 R% v, r9 M
- *(res_buff.cur_buffer->data_size) = 0;: y6 z+ m. r- x9 T3 d2 P& o5 ^; v
- res_buff.cur_buffer = next_read;' J, v* y5 j( J) y
- }
4 J- u! E+ k+ F/ `- \4 ? - //清楚中断标识! L& l' N9 A. f
- *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status* i$ `% J9 ]1 q1 z. ?
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部 - W" R4 m. U% M4 k- n
- ; s! m: e2 `5 y+ I* k4 I# B: v
- . d/ H% L+ `4 Y# r: R
- return IRQ_HANDLED;8 {# L8 q+ J' z5 f3 y
- * ^( ?2 Y3 C& m' j6 j$ S
- }
8 w* H1 B( w/ x" Z# c4 R
) J2 }. d4 ]6 Q5 A- //文件打开函数! p% R, e1 i; s3 v! p7 a
- static int protocol_open(struct inode *inode, struct file *file)" h, n+ N8 E& G3 V/ V5 {
- {) X# g7 e7 S. |6 ~
- int result = 0;) c4 A; F5 ]9 g! B: x
- if(!atomic_dec_and_test(&dev_available)): M0 M, i1 n* o2 d5 W9 a
- {
9 H% X- p1 e1 a+ C8 ~) a - atomic_inc(&dev_available);$ Y7 t' }# ]5 b% w/ g+ D0 G4 r1 W
- return -EBUSY;//设备已经被打开 S+ x5 p1 k: q2 \- Z3 a
- }
8 Q# u: j6 p( A+ C9 m/ ]( V1 P - printk (KERN_ALERT "\nprotrol driver open\n");
& ~' S+ s; Q3 I3 i# p - return 0;8 Q$ n: K; Z" ~5 f
- }3 n7 Z8 [4 k4 ]# s+ Y; ~4 p
- / x2 | M) ~% ~1 w
- //文件释放函数
* `( q+ F. p p3 P - static int protocol_release(struct inode *inode, struct file *filp)
# k( D( r) u: C - {
) p& K% r; k# g' s' h" n - atomic_inc(&dev_available);//释放设备,原子变量加18 W0 h) n. ?5 Q/ A
- printk (KERN_ALERT "device released\n");
X2 I& f, ~! I$ F L - return 0;* u7 S& I4 W5 x6 B$ J! ^6 U' q# p. H
- }
- G# e5 O9 L" h6 D; ~6 u - _0 B% ]- H3 m+ f0 L
- //文件读函数
+ ^% P8 A& q; |6 p! p - static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)1 z! z6 x' v) M+ v
- {
" }7 w& ~' w5 h4 A1 n; w+ p - int ret = 0;
1 p4 e$ E) |. h - //定义等待队列! t. L+ [3 X. p
- DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列
" @. ^; o/ w1 N% F# ]% B - add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
6 x* v6 _# p( U& l; N - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
% i& \8 X. k& [3 t - {
; C+ t2 B4 ^: a- \# ]! M+ d. O) @ - //printk(KERN_ALERT"\nbuffer no data\n");3 h5 Q# f9 K% ~8 k. K0 w7 X' z
- //如果是非阻塞方式读取,则直接跳出; k$ b4 u, s7 m8 u, E! z
- if(filp->f_flags & O_NONBLOCK)1 C' ? z$ s2 X2 @# b" f0 U3 e
- {1 e& S! G3 c1 v; p7 A
- ret = -EAGAIN;1 ?# c& \# L. K% Z8 ]
- goto out;
" k! B4 r$ }7 N+ z/ A- Q - }
* t4 g1 n$ w, c. l7 X9 z1 K( o - //阻塞当前进程,放弃cpu资源
4 _2 q$ ~) x* S9 r3 \1 ] - read_quest = 1;0 E9 {# j$ O$ Y5 e4 ~
- __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠
; I F" f$ |. { f9 f8 b - schedule();//调度其他进程运行
- ]+ q3 ~, d- T3 s) |$ M - if(signal_pending(current))
4 O. C a2 x" n2 \ - {& m) s$ W2 a8 G- z
- //如果是因为信号被唤醒,则返回到系统调用之前的地方
p8 c& T; Q( z - ret = -ERESTARTSYS;# O, w7 ?( E- |+ ]/ O. ]
- goto out;! ^; S% N- k* C) q7 U
- }
2 r% h7 A5 Z& o" [ - }8 d7 Q7 {% V1 D, T+ R
- //将数据拷贝到用户空间
- R( C$ m9 j$ F& z7 L7 J- A2 i - ret = k_linkQueue_getData(&queue, dst);/ @* G2 x" l- E7 E1 P1 W
- if(ret == 0)
8 Z$ H3 l; D: [+ }" @+ j+ b: l - {9 u3 W N! t( @, [
- //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);/ V7 i5 k8 p8 W- m# U) Z' N
- }
, u4 P# @* R# E - out:
5 S7 V; A7 c/ o- p8 p5 @ - remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列
$ E1 Z' `+ Y& d+ I7 B/ r - set_current_state(TASK_RUNNING);//设置当前进程为运行状态5 f& j! o) S6 p: B
- return ret;
@' i+ g8 Y" ~' t* V4 { - }; k7 J, \; [; J$ m2 E) ~
4 p3 B5 t% G) i- K) t
* Q2 l! j+ _7 h. k# E1 x- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)( i. G( J: S5 |$ z' a& V# ^8 Z
- {. i3 m9 t B( y
- return 0;
' x7 P1 u8 N, E, \ - }
( b; O/ V3 f4 X0 F* _) O( o3 o - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行) ]4 s7 S5 |& \) L# I
- open()、release()、ioctl()协同调用时被调用*/) E! u' s2 ~! _# Z
- static const struct file_operations protocol_fops =" P) y* V- y# ^: D; n
- {, B; b- A! }% v& x3 Y! l
- .owner = THIS_MODULE,/ d; `- q& P: i& Q
- .open = protocol_open,7 W; S" x! h2 |* ^
- .release = protocol_release,; }9 Q. ^2 R! e8 W
- .read = protocol_read,+ q `* P6 `9 W$ S
- // .write = protocol_write," c! c* {1 ]5 _9 j: H
- .unlocked_ioctl=protocol_ioctl,
. z* ]' o3 O8 c. S# M9 ~) A; T - };
- G r+ i2 d8 S* v - 0 _+ ~5 j4 f1 g' a8 S
- /*设备驱动模块加载函数*/ C+ `& f& g2 e7 C7 I
- int __init protocol_init(void)
7 M8 A" ?& p8 c! Z - {
, p$ P/ ^3 J. `! I" t$ K - int ret = 0;
% q G/ H! H. w: A6 [" m. j - int result = 0;. d& r U" O, \9 J9 h6 t1 W
- //申请注册设备号(动态)
9 U% R: v8 e' u- B8 z! F - ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); 7 C( v6 p! n! t1 ]" V& x
- if(ret < 0)% \% A/ k% b- P; u, E2 V- _
- {& x- m9 D( t7 v' W
- printk(KERN_EMERG "alloc_chrdev_region failed\n");
: ^% L. c* K' \4 M K3 ` - return 0;
- f; O& F, ~" Q - }/ y! {5 N- {+ c3 O R/ e0 U; s8 R
- //分配cdev/ `# {% o* W% K( _! j1 `
- protocol_cdev = cdev_alloc();% f- _8 X$ m* L. \$ V
- if(protocol_cdev == NULL)
' U+ s1 Y2 Y1 r - {
$ Y7 d4 |& Z: F5 ^) y - printk(KERN_EMERG "Cannot alloc cdev\n");+ c* `' w7 k, y
- return 0;
! x# M, R- }2 B: v4 A u6 F - }8 E: @+ ^& f2 J/ V5 x7 v' Y# I
- //初始化cdev
7 S4 r# v& h0 H5 X' Y, |8 D - cdev_init(protocol_cdev,&protocol_fops);. U2 z, ]8 N$ @' }
- protocol_cdev->owner=THIS_MODULE;9 o$ K+ B4 z9 o" L$ X( \1 {
- //注册cdev. g5 L" E: s/ d! U$ w6 [
- cdev_add(protocol_cdev, protocol_dev_no, 1); 4 X# H0 W3 u: X, S& L
- //创建一个类9 }; }7 A, d4 j# R8 a& v# k
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);6 b0 B8 N5 I% C
- //创建设备节点5 `' }/ w. g9 O
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);" \- o8 L. w# O
- 7 _6 @) K- z0 m9 A% h( I
-
1 |0 p9 O, e3 ?& {; Q1 l$ N - //申请链式循环队列作为缓冲区DSP数据帧的缓冲区2 F5 y- z& Q: u& G% F0 u/ M
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区; X$ k/ V, Z1 @& A6 i/ c
- \: A1 X `' T+ u4 G
- //映射ARM的核间通讯寄存器5 y9 @( k; A- ~7 ?8 \ ~2 d' a6 I
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
$ E2 _( u5 S0 t$ s - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);7 c2 f% Q# }# h% ^. y
- //将物理地址映射到内核空间
6 s5 s5 R6 m3 f9 s - mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);$ q. i" v; ^. t4 h0 K; P( t
- //共享内存初始化
+ i5 x3 G# A0 p - SHM_ARM_Init((unsigned char *)mem_base);" h) ^8 c$ B9 L2 K# T! h
- /*申请中断*/
3 I; G n* V! ~2 j+ B' w( h - 5 \* m7 D: e1 \9 S/ A9 |1 b' T
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);
5 J$ P- V' ]5 F1 @8 W/ \$ t - if(result != 0)
% J/ b; y( {2 S- C! R8 W# O& E - {
% _4 M' y0 T; O; \, F - if(result == -EINVAL)4 K5 q( f$ O) E* S) c
- {
$ f! S1 x) C; z! v - printk(KERN_ALERT "irq request err:-EINVAL\n");4 U p9 w1 {0 x/ \- m5 {) C2 p# X
- }- ?. W! S* I! G) W' a1 D
- else if(result == -EBUSY)
$ Y( B- ^" F9 {( e0 v - {8 E5 A/ s" L) g8 v1 M7 m' Q, E* T
- printk(KERN_ALERT "irq request err:--EBUSY\n");
9 R4 V+ R7 n2 O% | - }
* L+ Y- G& d/ k' O4 @ - else
0 A9 `- t! s: P) C. s; t! n - {) O/ \7 t A- b2 p: L# Y
- printk(KERN_ALERT "irq request err: unknown\n");
3 E4 K6 w' y$ H9 `. V) x - }. _) `. b+ ^/ G+ M$ k3 Q: W
- return result;
0 `: o) l: m' ?# t% S - }
; J! S T! n& f6 x6 [# } - return 0;
! p- a# v. s: [5 U+ z6 k' B - }+ ~' _5 F7 e- j. |0 J
( B) y% B! d% z, S+ E- /*设备驱动模块卸载函数*/
- u2 }, p, l7 ~+ i2 u" }+ A8 z* ` - void __exit protocol_exit(void) R+ l$ w7 T( ^
- {
) m0 \4 x5 c G2 A8 v - /*释放中断*/0 g3 d7 b+ V" C' t
- free_irq(IRQ_DA8XX_CHIPINT0, NULL);
: ^/ V! N( D# J2 |( I - //释放帧缓冲的内存5 E" [$ ]+ d; O/ y- D8 |5 c
- k_linkQueue_release(&queue);& b/ Z( O( o U& v6 q
- //释放寄存器映射* }% L9 ]# Q! K, f* L% x2 L* z
- iounmap(R_CHIPSIG);
' @9 n: D; ` g, h8 u+ T! C - iounmap(R_CHIPSIG_CLR);
5 {1 u/ f: |2 p1 o - cdev_del(protocol_cdev); //删除cdev# ^/ e* N1 [( \- e5 u3 K! d/ O4 r
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号
' r0 B3 Z( @7 J7 ]& H0 W - device_destroy(protocol_class, protocol_dev_no); //销毁设备节点3 N1 n2 ^3 v7 a7 B' |: f6 h- [
- class_destroy(protocol_class); //销毁设备类- Z! { U" s( t
- printk(KERN_ALERT "exit success\n");" S @* |/ a5 R8 C+ B
5 ]9 v7 T! y. y- }. Z5 N9 [2 ]! d; n' H
- //驱动其他部分省略
复制代码 ( h8 @, P' H0 D2 v" F, c2 }8 }7 \: ^
# ]$ M/ j# S& r |