本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑
# Q% d0 f" u$ q" t( k- c+ H; w( f
{( I) y! d t& t8 d" F& z3 i项目要求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 P5 z0 T. c7 w9 b
- " O2 J: N1 o! \% c1 p+ q4 o: ?
- //引入其他模块函数和变量/ l& |; n$ c X. a& ~; u, [
- extern Ping_Pong_Buffer res_buff;$ {. u; b$ T+ K, `
# u+ d# e' ^; n/ K& \3 f# Q/ _ W- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列
* h( }! W, i/ L2 q' A. J% D - extern void k_linkQueue_release(linkQueue *queue);//释放链队列
0 H+ c) i* `+ @+ X. F c: m6 t5 e - extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据# Q+ j: I1 {' M% d0 G; W
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据
, O- K: y8 Z! m4 s# O K. \4 V& w: H - " [. j# U! e& }. a$ f- A+ q
- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化
2 X$ }& U! W3 c G9 C
$ K# a# V+ q, V' A- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1
1 _ X: F6 ^; t* ?' K7 P - //设置主从设备号) V6 X/ b: {3 N) u% I# \
- #define PROTOCOL_MAJOR 1
" N& z. L- y: H9 } - #define PROTOCOL_MINOR 0
4 ^; u1 I) G) v8 B8 O! Y) y& g - " W/ R7 \( E V, o/ \2 W
- $ _1 ?5 V2 P% w- @. k9 U# c1 E
! l0 c! ^9 D" U- //定义设备驱动的名字或设备节点的名字
* d$ w. B- \: ?; s6 b - #define DEVICE_NAME "protocol_driver"
$ W; R8 P2 Q: j3 ]3 c- a - . n/ ?( T) A, G3 v
- # a9 } T+ C7 F
- //定义全局的循环队列作为数据缓冲区
' p) ?- B. m z, b2 {. ?+ K% W, J) ] - k_linkQueue queue;
4 D$ l. O9 h+ v {+ l! J - " S% d( r+ a& `% C" A% k
- //寄存器地址映射全局变量
) O, N" Q7 g6 O+ @5 ] - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器! z# F: t# u8 R) _6 U" ~3 s
- unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器
! O( [ ~& F8 i7 t* f9 G
8 M/ N# f9 e$ H- //物理内存映射全局变量
7 V- M# ~# l" z, y2 t# s' I6 M - volatile void *mem_base = NULL;1 g( B, ^. W& J6 G% I( Q: y# t! R+ d
- volatile unsigned char *cur_buf_ptr = NULL;
! b6 Y+ R& [. B - volatile unsigned char *data_ready_ptr = NULL;
3 T) }8 I1 \& v+ k' |4 Y - 9 C' a0 l1 e& q# j' d! X
- F1 R9 V6 s. R0 I7 G6 i
- & R( h7 G) g7 a3 X0 ~! K" k
- //定义读数据等待队列头,IO阻塞
5 n6 m+ H% B, c" e! u+ Q) v4 \ - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);$ l/ v! R$ B6 G0 K H' m! {. M
- 4 y9 Z9 a9 _+ Y" W
- //定义原子变量' E* t- z1 @. f, d
- static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备
! t' R# c9 [, C# {3 z- [ - 5 K: ^+ |0 Q' e" f
- # g+ ]+ V: q8 c5 C# ]9 n" g3 b @
- //定义设备类
7 ? @8 K1 b. r8 x - static struct class *protocol_class;! c S! n* ]' G8 \, L4 M b
- struct cdev *protocol_cdev;5 a5 X5 X$ s7 |/ N8 r' {+ K
- dev_t protocol_dev_no;
' E; L2 {/ D( G, A" H4 C
* Z6 m S% W1 N" Z$ o7 Z, W/ Y- /*定义tasklet和声明底半部函数并关联*/( I. Y7 R \, K2 @ Q3 p7 _
- void read_data_tasklet(unsigned long);, `& \5 d: a7 @ a
- : ^9 c) } ~* K+ \
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);5 a. ?; g3 X" l b1 H' r
- //将CHIPINT0_tasklet与read_data绑定,传入参数0$ S0 r! |9 h6 p, F: c4 a
- . x0 B# P: x! M5 ^
- /*中断处理底半部, 拷贝内存*// R& Z$ _8 r( w! o* x9 @
- void read_data(unsigned long a)
. J, y$ G7 ~! L! N- Q) z! y. e - {1 ~& j# i/ p. C9 C
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1
( ]5 s$ ~2 b2 [9 W1 v - {. A, l# w4 r1 y5 {
- read_quest = 0;; ~* m7 @$ e' E
- wake_up_interruptible(&wait_queue_head);//唤醒读等待队列3 |% \9 y* V+ b1 d: I8 i) E, B4 Z
- }
+ N6 U; O) u) c
9 G" ^& ^. u: R! _- {- }4 f3 p, W: a4 r+ M5 x% A$ R
+ W- o% O( X) P- /*中断处理顶半部*/& S+ h0 F3 N, `0 @5 \1 s
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)
( s# s) H5 o! O" r; U1 Q0 H/ m - {
5 e- x( C \% G/ y7 L - //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样) d" t0 m" K! a" l7 @. S
- volatile Buffer_Type *next_read;0 H- t- |. q b& h$ W
- //如果DSP数据已经ready! s+ }/ P- y0 c6 l' ~+ A7 p
- if(*(res_buff.cur_buffer->data_ready) == 1), C! |( w, J6 o& _4 r- Y
- {
8 L3 V- x& Q8 T: \2 ` - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer
. ?+ u" R; m) N% h3 @2 b - {, Z5 p p& T) R* z$ H4 O
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer2 u& N% P% ^0 n$ s
- //printk(KERN_ALERT"read ping\n");; O" s+ a. \( M0 h
- }
* v2 X. ~; y7 q4 e" e2 i - else* G% ]8 X5 I- V7 G. P8 j1 N
- {! Z/ Q- a3 P. W4 b8 R) Z1 u
- next_read = &res_buff.ping_buffer;//下一次中断读ping buffer
" u5 f. I" o6 A - //printk(KERN_ALERT"read pong\n");; o! Y! c* W9 q! I# y! ~
- }1 l$ m1 {4 @! b& }1 H0 r
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer
: l' c, O+ w9 f! }# I- O$ {' C - //将数据插入链队列! i$ k0 \) E, N$ Q% J& M, ]
- k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);
9 ~: _' n1 T' l2 H# R! W - //标识位都重置% d' S2 {) r$ R7 R$ d
- *(res_buff.cur_buffer->data_ready) = 0;" h8 W, _1 @: s* H R
- *(res_buff.cur_buffer->data_size) = 0;
8 h9 v- T2 `/ Y8 y" |3 k - res_buff.cur_buffer = next_read;
/ q/ m2 u: u" g" G - }
, o5 q' |( R9 b4 j5 l( @, X7 y - //清楚中断标识
7 n4 W; Y* _) J0 R8 v+ ^2 c" F; g2 e0 Q - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status2 ~, X7 U' ], c! x, G O
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部 Z% y5 z! W3 a
- 2 {3 x U0 ^1 _7 J( f ]" P4 W3 c
5 t! e. P3 z' c) m- return IRQ_HANDLED;
, @4 H# d9 E% ~- t* Z
& C9 r8 l' U1 ?" w( B5 y9 ?- }
6 n( ^4 a# U7 w$ f$ D1 g1 m3 O1 P
* F* x w3 [: ]& O5 V- //文件打开函数
& R- a- J. ^; T: }0 S P - static int protocol_open(struct inode *inode, struct file *file)
! T1 J- F) {1 R/ }2 [& a' O - {
+ [8 I3 ]. @ i- }" X - int result = 0;
8 }+ u. W0 N4 O) b1 z- K - if(!atomic_dec_and_test(&dev_available))
7 V' I6 L! E& f: h( g/ | - {; g I6 H: A0 u5 v6 J9 ^
- atomic_inc(&dev_available);
3 u1 s* W3 k+ D - return -EBUSY;//设备已经被打开1 o$ D9 S2 N0 d0 b4 k. r3 ~
- }. ]8 e. M& v4 n+ ^2 E5 d& K: w
- printk (KERN_ALERT "\nprotrol driver open\n");
3 j% P# p; I' d1 } d' E5 [ - return 0;: B! Y# d3 D+ i t' t5 [3 p
- }
0 Q2 @& t5 [! E% V8 f' S$ Q: z; A+ M - 3 L; F# K; u; c
- //文件释放函数
0 b" e6 Q2 L8 J5 g" X' H - static int protocol_release(struct inode *inode, struct file *filp)
6 W/ k0 {7 Z+ L( v n+ ^ - {8 ?' Y6 }/ M! F$ S9 d
- atomic_inc(&dev_available);//释放设备,原子变量加1
! X9 g4 i p. ?8 v. L7 B - printk (KERN_ALERT "device released\n");
1 _5 p8 z" w" d1 `' Z" j9 i - return 0;
3 |% k/ v' X- D/ S6 r" C - }
1 g) T1 `) ^( o3 t' F1 X
) ~2 A8 o' L5 v; g# C E3 {- //文件读函数8 M, L3 x$ U& l+ H4 o
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)
: b/ L& N; Z4 `* ^6 Z( S( ] - {7 _2 [' p( R9 w
- int ret = 0;8 `) k( g7 f# R
- //定义等待队列 }/ L+ |- J' ?2 V3 L" J
- DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列1 U( e) r v4 m8 d' o2 i F& f$ k9 D
- add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列' u( N E5 b+ F4 F
- if(queue.remainNumber == queue.blockNumber)//当前buffer没数据/ y! w9 l5 y& M
- {
( |! O2 H! F* Y. L - //printk(KERN_ALERT"\nbuffer no data\n");
* G1 }9 H6 j% O- A* t - //如果是非阻塞方式读取,则直接跳出
) o2 j5 j8 R \) v U# o/ B - if(filp->f_flags & O_NONBLOCK)( d4 B" O1 [) t* k1 `
- {
/ D# {1 f1 N% S+ I# b - ret = -EAGAIN; a3 E, a8 Y0 ]4 `! m# |$ n
- goto out;9 D. y+ R! Q" c# ^# V6 u
- }
, s5 p _$ o/ N - //阻塞当前进程,放弃cpu资源1 G* V i$ Y: E; N9 V9 D
- read_quest = 1;
7 q5 P2 |9 N2 w! Y/ f - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠. [. s: l/ n" b3 a. B) n1 Q7 f
- schedule();//调度其他进程运行
& b; G* A c) t2 Y5 n9 V - if(signal_pending(current))
; |" ]0 c! j6 r7 e" s7 K, v, k - {0 J7 S9 n" y8 }/ y9 x0 W
- //如果是因为信号被唤醒,则返回到系统调用之前的地方/ V# y( P5 W& }+ P8 N" U. K
- ret = -ERESTARTSYS;
+ {. {( f# c$ D: u - goto out;& K0 }/ [ b: {" e9 {9 s/ e
- }
" z* j4 t' m Q5 Y* b9 h) ~/ W - }
' v; R* ]* e8 R2 p2 \# N* w& K - //将数据拷贝到用户空间
* ^5 a5 s8 i# K- }' m7 T1 D- \ - ret = k_linkQueue_getData(&queue, dst);
6 O) G) [$ \7 s7 x- z) N - if(ret == 0)$ M+ W) ]. N/ m& x# l/ \
- {( L$ ?" ~1 b: E7 W9 B& }* S
- //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);: d6 t& O C. I* ^
- }
0 W9 M3 O/ U+ I. z4 \ - out:
2 x8 w/ u$ v& T! ~ h. B - remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列 j; y N; e4 q! k& t0 K" v
- set_current_state(TASK_RUNNING);//设置当前进程为运行状态3 Y) j- d. R4 N6 _# {
- return ret;9 _$ B. T0 {, C* \; x6 ?
- }
" \+ ?" Y) k5 h1 d2 K/ U" a
) s. Z; L. X2 i
p/ P! w" r( h) u- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)
K1 u6 }' r, z/ M" ~( {" I1 s - {8 s" c Y) F( r% i: S0 I" @2 H* b
- return 0;3 b. ?9 r4 U, r) a* z
- }5 K4 f0 ]5 M! e
- /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行" f' \! V5 {$ N2 l5 v: g: N& K
- open()、release()、ioctl()协同调用时被调用*/
$ ?2 |% L0 T; a$ J, u - static const struct file_operations protocol_fops =1 f; E& Q9 J: ~/ Q( e
- {% o5 o. r% z: b j. }
- .owner = THIS_MODULE,
* i9 O7 V5 H5 G - .open = protocol_open,! X( |7 D1 `; I
- .release = protocol_release,
: `4 }6 _2 J$ p% _ - .read = protocol_read,, ^4 Q4 u- o- j; V. s. O
- // .write = protocol_write,
" o9 \0 s, M5 e8 p! j - .unlocked_ioctl=protocol_ioctl,8 ~1 ^; X7 C+ y, T: n. p H0 p
- };6 c, p7 F' `$ r4 o% @+ x# c
0 C+ C4 t5 b$ L: r" |1 X* ]' Y- /*设备驱动模块加载函数*/
3 } X1 j: f- a: U - int __init protocol_init(void)0 m5 y* S0 A/ I. b, a( C' u& `
- {* ?7 L7 ]0 b; c, g6 W2 z/ j) @
- int ret = 0;
% e/ ~' S/ D7 F - int result = 0;
y* x( X: s5 b5 Z3 w) i; S' H - //申请注册设备号(动态)
9 X# p9 y8 L& A - ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME);
2 |1 a4 _4 J. \4 u6 |6 k, K2 G - if(ret < 0)
{5 n0 f% z c. \, e6 i0 F9 I - {; l0 d, X' f4 l5 y2 D) h/ d' @
- printk(KERN_EMERG "alloc_chrdev_region failed\n");
! Z* A1 ?# K. \+ a5 W - return 0;
2 y2 w" r6 [2 ]' W9 L) a - } j4 n' |% a. c! u8 g: Y& ~3 w
- //分配cdev1 [( ^- a" l, U2 a* H3 L
- protocol_cdev = cdev_alloc();% v% {& m8 h; h
- if(protocol_cdev == NULL)$ f+ @( u. `. R0 G* l3 \
- {. ~5 D; i6 d$ K+ i# m3 S4 c- U1 r
- printk(KERN_EMERG "Cannot alloc cdev\n");$ U' Z# e) V/ E/ ]7 K- }
- return 0;
+ Y; ? G8 L' R - }% t d) a( U+ y, y( B
- //初始化cdev8 a8 n0 r! F- c" h8 ^9 [
- cdev_init(protocol_cdev,&protocol_fops);
) C- J; d! t1 E2 i ` - protocol_cdev->owner=THIS_MODULE;# \7 w4 Q$ R! \! C% M C% t
- //注册cdev
( {; z4 ]& x/ _0 ^; } - cdev_add(protocol_cdev, protocol_dev_no, 1); ( W' w3 G" `' a7 M
- //创建一个类8 f3 t, F2 t" a$ _$ g
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);4 y. N0 i) t0 D" O* { d0 [- a
- //创建设备节点
* o% ], K2 ^1 X, o - device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);3 W+ j( T$ j0 E- v
- / f; M# W# p, c( M# _$ d. u
- 9 s+ U, A0 p2 R& x) |4 D
- //申请链式循环队列作为缓冲区DSP数据帧的缓冲区
: ^! ?* F9 X$ Q8 Y# X: D - k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区; G- b- |( D' I2 n, A
) u' o- D; z5 P! {* m- //映射ARM的核间通讯寄存器
2 @& t( V# n) s. I. b- g - R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
0 z* A3 ~+ Q1 l' N8 ` - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);
0 ~2 K0 X* n* W. V% }+ h0 ] - //将物理地址映射到内核空间
! n& o8 [+ Z. M1 {5 O- y - mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);3 l: p& m5 s6 P* F
- //共享内存初始化4 h3 [) f7 R" f- x' `* u
- SHM_ARM_Init((unsigned char *)mem_base);
; Z; m* r2 w& Q/ j3 v - /*申请中断*/
. M, Z% k# {2 M/ S - : Y: Y# i1 V) a0 m
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);9 N* g% Y) Q% H, D5 _ q
- if(result != 0)' C1 \% ^4 ^; F
- {1 v6 e u4 [- x$ D, z/ X
- if(result == -EINVAL)
- x+ D$ l& V6 [0 k& P/ W' T& i - {
8 `( p6 K% _9 V' E4 `- Y - printk(KERN_ALERT "irq request err:-EINVAL\n");
' b( I8 i0 x: |; l# o' F - }
% v# w! D. } u$ v% W - else if(result == -EBUSY)
3 f- @$ o4 e3 O [- u/ i1 j - {. x' Q4 k$ z7 m3 L' j9 e& \& x' B
- printk(KERN_ALERT "irq request err:--EBUSY\n");5 O! T; y( M% }: r# f. s
- }
' S0 H# {. u; U7 A - else
2 y, E, v- T8 X" n - {
( p0 c4 F$ K7 r$ M! w) w5 [ - printk(KERN_ALERT "irq request err: unknown\n");
4 r1 ], e0 w7 N7 ?' {+ M3 R - }/ {4 j9 D6 d1 w, s, R
- return result;, H/ h: U4 B" Y+ [0 P
- }9 d8 d& F: @: g* n
- return 0;3 h$ @, y, d! g8 {
- }
' L9 j/ u( { ]1 x6 g6 J7 p" @
! M( K e. R+ J0 W/ [! T- /*设备驱动模块卸载函数*/
. g! |: C3 r2 H$ \ - void __exit protocol_exit(void)' t" W7 j$ S& `
- {
0 Y0 o0 s- f! [+ v9 v1 L - /*释放中断*/+ V1 u$ Y. ~" c9 l) G) `+ `
- free_irq(IRQ_DA8XX_CHIPINT0, NULL);% N/ E9 j& ?; H5 J
- //释放帧缓冲的内存
' s7 S: @7 H3 T2 I2 |% B - k_linkQueue_release(&queue);
$ r4 W$ p5 C% i" e% O+ X - //释放寄存器映射
d9 m+ a( ]- {1 g5 S4 M" g/ L - iounmap(R_CHIPSIG);+ A. r( X' y5 j' J# S
- iounmap(R_CHIPSIG_CLR);
- P l. H* o# }1 y1 t6 P G: [& { - cdev_del(protocol_cdev); //删除cdev
& ?! O& Z0 B, @( U. |2 e" n! P; T - unregister_chrdev_region(protocol_dev_no, 1); //注销设备号9 i6 Q; {: J: v. x6 Q4 s
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点$ q% i" p$ K% o6 T7 g4 \0 @+ E
- class_destroy(protocol_class); //销毁设备类( @* p, L/ v9 p6 o
- printk(KERN_ALERT "exit success\n");6 f3 U8 d& x1 B: H; K0 p# I
- ) C2 v7 ]$ ]& g
- }- n; L$ [! w/ \6 `% C. m
- //驱动其他部分省略
复制代码
" s0 `. x6 _; X8 l* z7 W0 {& V* i4 H2 J0 r. |
|