本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑 $ C" M0 t6 O& G: P e- @; R
. Z* u- k( {* `* 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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略; h# S* K" L6 h
# j# D8 f1 H0 e. M+ c- //引入其他模块函数和变量1 i- `: ?- k+ t* ?+ _
- extern Ping_Pong_Buffer res_buff;
- K5 }3 u6 h' f) `4 X3 \ - 3 o6 w# T+ {) Z: F$ h
- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列
2 ]! Q+ O, y4 _, z# S5 } - extern void k_linkQueue_release(linkQueue *queue);//释放链队列* g" ~( f# @* {5 x8 Y
- extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据- O8 U* j7 L* B
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据2 r7 h3 ]/ J& R2 V1 a
z, d( d; S E- Z5 ]( Y& x: {- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化2 M- x l$ G1 _- t* {
- 2 H) C6 P9 u# T( f1 y
- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1& s) d _1 X* j, N; [2 p+ ~
- //设置主从设备号
9 b+ G; ^" w3 n* j9 b; _ - #define PROTOCOL_MAJOR 1
8 D: r; u* V7 J7 e1 a9 q - #define PROTOCOL_MINOR 0- K. d# l+ \) ?6 [9 m5 p
- + F; Z8 m$ E9 P4 d& o
- 7 M7 J4 b, m8 G* [! c* P, |# N( E J
- ) }; I' `, y, `: k0 H. z% d
- //定义设备驱动的名字或设备节点的名字
0 H+ t4 q6 z4 O# z# A) l: g - #define DEVICE_NAME "protocol_driver"2 z D7 G6 x4 V- c9 \
1 B3 D9 ~7 t& W% y( r# Q- $ q2 j% J8 ^! ?0 |
- //定义全局的循环队列作为数据缓冲区
6 i% M7 i7 i5 H) q3 Z: | - k_linkQueue queue;2 X- F! r' t; }3 Y( B0 j* d) O% }
3 S& S d+ s/ N* E- //寄存器地址映射全局变量
) R) {5 Y, l& `5 M% Q6 Z* @ - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器
) R, T% D" q- l6 K2 X0 L/ A - unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器: e$ x. k/ b3 a+ x1 |
7 P& W( S; B6 H, ~& c4 E- //物理内存映射全局变量
9 _9 g8 H. r( P" M3 h - volatile void *mem_base = NULL;; q5 G7 u: |! z! t# @
- volatile unsigned char *cur_buf_ptr = NULL;5 D; s j: T5 L: e. N/ N d
- volatile unsigned char *data_ready_ptr = NULL;
& i& j+ f, s3 U( p
) M$ Z) W7 o% r& W
0 h" y1 K1 I7 p1 L* P- }7 h6 @' A6 @
; Q G% A( R/ k# ?0 O, J2 P- //定义读数据等待队列头,IO阻塞0 A: |, c0 S+ I$ T* s3 J; {
- DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);2 x: a3 \1 b! @7 @
- * R# m$ F8 W: T( N8 N/ S% h
- //定义原子变量
7 d3 i j6 ]" | - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备% S3 I3 `, O+ E3 \) ?
- , M/ z6 Y+ V9 _$ o) S, B
3 `' v: H6 s& M6 l! `4 X- //定义设备类
( `- c3 I, M) |7 i - static struct class *protocol_class;
/ p6 Q. X% H9 ?) G: B5 } - struct cdev *protocol_cdev;
/ I' O! Y5 N- B" H' n: ~" C - dev_t protocol_dev_no;6 c7 v1 L. z4 I( l! G$ l$ F
0 w* ]+ g/ Q, x' @: z5 \+ \- /*定义tasklet和声明底半部函数并关联*/% O1 J) \0 Y2 e0 u
- void read_data_tasklet(unsigned long);0 s6 A; t7 s; j/ y2 W! H
- - S ~; ?! C% {! H
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
' J' U( F# _9 D9 w! f7 }; l% ]* u - //将CHIPINT0_tasklet与read_data绑定,传入参数0: s& q9 B% c. _/ z) J: [9 j4 K) h
- % {8 m6 a5 A6 }& \* L' `) x2 X
- /*中断处理底半部, 拷贝内存*/
* k# j# a1 p# g; O& | - void read_data(unsigned long a)3 K- w, K% e% U) s- I
- {+ U: o3 z0 N5 l2 ^$ Z5 h8 {
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1
' C9 c& z/ e/ Z( f+ ~! i& k" ]$ \' E - {
+ U) b/ d) s; u( t - read_quest = 0;
; z# C' {/ o' T4 }" s$ T - wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
( N& R# ^( @+ k - }& F2 z, Z; _- c$ r; C
- 4 B9 @6 V1 o) q/ O0 `+ T8 E
- }" Q8 k2 t/ M$ [( n3 _* E( z
9 L. }2 k2 p5 W5 o! P- /*中断处理顶半部*/
; R- `4 _' |' N% x+ U1 M- S - irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)# ?9 p6 \) j/ Z
- {" z& s; ~9 m) x' ?: ~9 ]; y
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
( g- P5 `, |4 B& S - volatile Buffer_Type *next_read;, g' S/ c; c5 }4 W
- //如果DSP数据已经ready
% B% l5 }5 |, W& I2 L8 I3 `% v4 L - if(*(res_buff.cur_buffer->data_ready) == 1)
, V' _" o0 `8 C# b) H) h# D - {# F; F) P; [8 |2 F4 I& v
- if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer( _0 e6 X/ @* V
- {
5 k( Q, G, I" z: b - next_read = &res_buff.pong_buffer;//下一次中断读pong buffer
- Z& D2 C- ?% w - //printk(KERN_ALERT"read ping\n");6 S- U; K7 X/ l7 A- I8 V
- }
, q: f" C5 C6 u8 W/ l, i - else
$ J2 o5 V7 k8 y6 k+ X - {$ [# \+ B9 n% L* V
- next_read = &res_buff.ping_buffer;//下一次中断读ping buffer3 h, C: e- C5 c) \8 h
- //printk(KERN_ALERT"read pong\n");
1 x4 @# ?! z& r3 W1 c' [9 F4 ?6 Q9 d - }& B; O6 D6 G9 k7 T# H
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer
& N; J3 R8 X( I0 D- Z - //将数据插入链队列
7 F. R; x& {( H) i* y/ R - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);/ C% n9 L7 j9 m& k0 }+ ]
- //标识位都重置 |) P# P% J+ D+ F7 d+ C
- *(res_buff.cur_buffer->data_ready) = 0;$ A1 z& k# i( `7 E4 r
- *(res_buff.cur_buffer->data_size) = 0;6 }# K; Y1 o9 q7 P$ L% S
- res_buff.cur_buffer = next_read;
+ L0 T( T- @, C3 Z) ?1 u7 s8 @ - }* X- w" _+ v9 P0 ^7 N* T
- //清楚中断标识) j7 }6 R) n. J- j
- *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status% [" T$ @" E. L1 C) r7 j
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部 # ^1 ]* K( s, ^2 x
) ]3 A S$ z% f {7 }
5 B+ l( z% H- t4 v: y( h* X% ~- return IRQ_HANDLED;
' B5 X; Z' b+ f$ } - * Y; }% Y( d7 i9 _0 l9 d* J: U' [
- }
) h% Z% a0 G0 T6 P; d8 j0 t: \ - 0 D' c5 d) T3 _# }) Q
- //文件打开函数" V) H1 `% l; B8 S3 z) ?
- static int protocol_open(struct inode *inode, struct file *file)
) z- k; j) |# }' }5 L5 C - {2 ]: e- m9 _$ J( }8 s3 X
- int result = 0;' S# s, q5 l9 _0 Q1 D0 [' U
- if(!atomic_dec_and_test(&dev_available))5 V) j/ m7 |; g$ A0 c
- {
" P7 D$ m. x j) | - atomic_inc(&dev_available);
* e5 ]" H. K( Z. c3 {- _ - return -EBUSY;//设备已经被打开0 T( J C$ b+ s8 J, y
- }$ |- t! Q7 y3 ]. M
- printk (KERN_ALERT "\nprotrol driver open\n");6 S0 p& \$ a4 V. k; z0 O% \5 Z
- return 0;
, M( C! z+ v9 c' D* Y0 Y5 j - }2 c7 }" }3 Q( p% X& Y. C
- : o! \7 @- ^2 z
- //文件释放函数& X1 Z L4 k3 H3 ?
- static int protocol_release(struct inode *inode, struct file *filp)
4 I6 r: t- ^. A% ?' M6 K& E - {
% X* [- g g* s7 s0 l9 F - atomic_inc(&dev_available);//释放设备,原子变量加1( u E3 g4 E+ V, O
- printk (KERN_ALERT "device released\n");4 ]+ I! n3 p# d0 }2 }$ U* `
- return 0;
' D* I. \( G+ r% A" |# h - }' J: q# R0 z3 a, M( Y% u- h$ i
8 x. P5 t& s1 ^" D1 q- //文件读函数$ }$ ]+ O4 o3 o1 K
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset) X/ G8 [% h h, E- w3 u' q$ T- o2 k( f
- {
9 c9 m; D2 g! G' |6 Y - int ret = 0;7 t4 l- K) Q8 j {0 ]
- //定义等待队列
! }9 S2 _3 g t - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列" g6 \# X' X5 u& V+ q
- add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
. D! p7 d: s. H) ^' X! m - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据! s! X; t# G7 w0 s) H ]/ }) p: N
- {
: c3 w5 {5 a: e# o3 i! w: ~ - //printk(KERN_ALERT"\nbuffer no data\n");( A2 \3 h5 N, n/ c9 ^1 i9 ]* p
- //如果是非阻塞方式读取,则直接跳出/ T% m ^2 [8 t. L8 @# N
- if(filp->f_flags & O_NONBLOCK)# e8 m' P4 v8 ^9 W
- {
7 {) C- X. p% r* z4 t0 _+ ` - ret = -EAGAIN;; ]) G5 H4 y$ I; C
- goto out;# _# a* T9 ?8 T: r9 N) k6 \
- }
" m3 v* G4 R1 Z - //阻塞当前进程,放弃cpu资源" B( c! i" p- j z1 ?3 z
- read_quest = 1;
3 _4 l% n4 F; D - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠
. u7 r( G: ^) z9 U J) V) n' u) j - schedule();//调度其他进程运行8 z; H, |5 w) R0 j* c0 b
- if(signal_pending(current))
3 ?/ U. K) L% F; M - {1 G- V0 Y5 c7 Z" K
- //如果是因为信号被唤醒,则返回到系统调用之前的地方4 u2 ~& w1 b! J, O6 _5 n
- ret = -ERESTARTSYS;! O, Z+ Z2 g8 _7 [4 {1 n: K b
- goto out;
3 ^: o+ K( u! i+ Z - }
% ^9 ?( ^" U z - } c# w, j$ A& @% m3 m/ B. U
- //将数据拷贝到用户空间
7 f" ^7 g! c- c! n - ret = k_linkQueue_getData(&queue, dst);, k7 s+ ? g w4 L" H
- if(ret == 0)
9 l- |- c% y- }- z/ z - {
# g0 l3 G) }3 t& [: J - //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);- X; }4 h5 U! F! J/ j
- }2 r; g) R, f8 F9 u _
- out:
) p- C) E2 j) E* ? - remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列8 S/ d- `5 r7 X5 [2 `* H1 i
- set_current_state(TASK_RUNNING);//设置当前进程为运行状态
% W+ ]0 f P4 u: j/ Y - return ret;
. M1 f9 ]+ \. C- J R |8 Q/ {6 u - }9 n/ e6 s5 g" P! q
- 2 `5 L# H, j+ O1 U! I6 ^
1 g3 b! {+ M+ l8 k+ ]* Z- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)2 D d( J3 D) ]4 G4 q
- {
0 ?! Y0 n9 y6 Q* _& U; ~1 P - return 0;
9 Z& L- `3 |6 Z, O( M3 d - }
5 a+ l# Y+ M& f - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行
9 D2 W6 y+ @* T6 j$ a - open()、release()、ioctl()协同调用时被调用*/
7 K: L7 Y: e/ H3 M: ^4 w# } - static const struct file_operations protocol_fops =" Z* U, |! { W5 I. J+ L6 u
- {
5 c( G- a2 ^, ?: o! G - .owner = THIS_MODULE,
8 u, {0 _" `* \1 a( ` - .open = protocol_open,0 g- @) Y4 `1 v' M2 k' Q5 K
- .release = protocol_release,. ]" z; s( }& U- |1 a( v/ V: G
- .read = protocol_read,! {9 ^( F W& q# M
- // .write = protocol_write,
8 m' K- G4 {& a4 l; d' e9 D, c, z; g - .unlocked_ioctl=protocol_ioctl,1 _9 h% }2 k) F0 x8 ?0 `4 v
- };
3 J5 E9 R2 a" h" |- d* s" l
! X, j9 Y! u! N( F( o. Q0 D6 i! n4 _& m G- /*设备驱动模块加载函数*/
$ K! i! W( q; _) n: c# H - int __init protocol_init(void)
6 B3 m! g& l+ r U: V1 J - {3 a7 q& e! W' S* u& J. P
- int ret = 0;
2 ~/ b6 w( r, ~( X9 c - int result = 0;
5 p3 j% P1 N+ ~/ \3 k L6 m# z" { - //申请注册设备号(动态)" t, y* |# S' m: E
- ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); $ F8 f: k. N, u9 |. K
- if(ret < 0)4 B5 g* a. X) L. T* \/ h R
- {
$ v9 D4 L# Q( ]( ~, G& r, Y1 U - printk(KERN_EMERG "alloc_chrdev_region failed\n");
! r% o; a ^8 e5 p- s - return 0;
9 S: Q* }) n" I! j# o2 o+ \ - }
4 ^/ e6 w/ I4 G& T( p1 p, y - //分配cdev
8 B. a: \* I: Z4 p* G# J - protocol_cdev = cdev_alloc(); N q! Z8 ]0 ?5 j: u4 H
- if(protocol_cdev == NULL)6 X( |+ P( I! b6 N! t, V& a
- {
. ?0 R; J8 U, n- u - printk(KERN_EMERG "Cannot alloc cdev\n");
. q2 s& A# V* n% i& n- | - return 0;9 U; F+ Q6 v; X7 }8 {+ n( q
- }
( l1 D: [3 ~( _3 ? - //初始化cdev
3 Q& g4 g$ z& E3 f7 K+ ^; A3 J7 \ - cdev_init(protocol_cdev,&protocol_fops);2 i- D/ q& m' @) R- G. x9 @
- protocol_cdev->owner=THIS_MODULE; g, I% g+ \2 A+ |
- //注册cdev; U7 q. Y( ^+ u/ P* P: S
- cdev_add(protocol_cdev, protocol_dev_no, 1); + G4 m# b6 s7 j1 ]
- //创建一个类
' p; ]& S$ _! Y4 m( `5 a! L# e4 ^ - protocol_class = class_create(THIS_MODULE, DEVICE_NAME);
V5 j' S( v6 o$ b - //创建设备节点: o9 v: M% i+ @, j: M
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);& C( R2 x8 i( |1 e7 h; X/ t
-
2 k t4 \: c# o& _) B -
# R) h! {- p E - //申请链式循环队列作为缓冲区DSP数据帧的缓冲区
2 F4 q' k, K4 z* J3 W - k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区3 B4 n% k6 w* ]
0 K& A. \8 E P: @$ O; i8 E( J- //映射ARM的核间通讯寄存器
" L3 ~7 I3 O9 O7 u - R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);2 e2 ~. n, m" b! U; x& I+ F* `/ N
- R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);+ ~ X! y6 B; G) D
- //将物理地址映射到内核空间
/ K; G6 r# B3 w j( J2 d Q - mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);
2 v# g$ P/ ], T5 w# {7 } - //共享内存初始化) f% Q0 v2 k" Q$ p
- SHM_ARM_Init((unsigned char *)mem_base);0 C. p( m1 n5 e. J; [* F$ Q
- /*申请中断*/
1 X2 Q4 O& Z' r
8 h' e/ U' {) y: |6 s! A- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);9 }( ]% T( T5 i) r
- if(result != 0), @$ W2 W1 k7 [
- {" P2 p! M3 N2 h( ^9 D* R3 E" G, n: ~
- if(result == -EINVAL)
1 n4 _* |6 d& \* v. g - {
) f' G3 s1 L, y; E+ u) C - printk(KERN_ALERT "irq request err:-EINVAL\n");
1 h2 Z* Q) ^! _6 ?' V - }8 T1 o' O) L Z2 U& _
- else if(result == -EBUSY), t5 c0 r2 L- n8 u4 G3 h2 j9 s, K
- {
2 ]. P1 K( D; k9 B2 ? - printk(KERN_ALERT "irq request err:--EBUSY\n");; F9 Y0 [1 x. _7 A/ [4 ]' p
- }
6 V8 I5 p# Y, E7 z( H# k - else
6 f( Q0 Y# D/ K7 ?# V& n - {
1 i7 p3 k! S( i j, V* z - printk(KERN_ALERT "irq request err: unknown\n");6 d1 K/ ?. e. U( P8 A8 ?8 Z9 W
- }
1 H! _3 R% t& K - return result;
* K4 [6 `' R* @ - }, R7 V# ]# J$ J& x- d
- return 0;
$ I2 I% r/ `7 B - }+ a4 j" Q6 Z' }' H0 u7 ~' Y( Y
. k, r% x/ f0 G- /*设备驱动模块卸载函数*/
) P2 ?# ?6 |! E4 [ - void __exit protocol_exit(void)
# G/ \3 X3 X& b2 X/ A - {
, |: y' M. {' A6 z+ ?" l - /*释放中断*/
Z0 d. i& U6 ]7 T" { - free_irq(IRQ_DA8XX_CHIPINT0, NULL);# n; B7 I) V* G G+ j5 h. v# V
- //释放帧缓冲的内存
! |2 l, o" |7 N3 G( l# \! f: e - k_linkQueue_release(&queue);' }" `: t4 P q5 \4 i5 Y
- //释放寄存器映射, C- r# Y- B9 A# ~3 f( j
- iounmap(R_CHIPSIG);
2 f( _& C6 h% i! A - iounmap(R_CHIPSIG_CLR);
, Q! |! ]+ F5 U: }+ C - cdev_del(protocol_cdev); //删除cdev
7 ?% z) H2 O' U/ C5 Q - unregister_chrdev_region(protocol_dev_no, 1); //注销设备号
) c& P2 e L0 V4 i* G6 K! x3 J - device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
& E- x: l7 {, c) Z; Z- \ - class_destroy(protocol_class); //销毁设备类) q M, t3 W( A1 k* {
- printk(KERN_ALERT "exit success\n");
+ W' a3 G2 s, e X8 G) M9 A. s
5 H0 `# i0 H2 ?$ G" `- }5 t9 R6 Z/ a" U1 C
- //驱动其他部分省略
复制代码 ! e" `+ F# c0 t: n6 b7 \# q
& C) `# q% I( T1 a V |