本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑
, l/ _" C6 r( t5 }! a$ C: L' |' @1 s0 x6 J& M
项目要求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 k: W" J% }3 k/ H# {# Z1 z7 ~& H0 M
" M3 Y( q: n- v: m/ Y& Z" h- //引入其他模块函数和变量
`5 y) ~8 @ b2 c - extern Ping_Pong_Buffer res_buff;1 b* V! S2 H( d: b
- " F$ m4 M# B" i. U# S9 ]% \- a
- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列: P% [' D% O, i* S
- extern void k_linkQueue_release(linkQueue *queue);//释放链队列
a, P5 A7 {% d - extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据7 v- \2 R5 i3 }0 P
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据0 r% z$ W$ }8 w/ A
- ) D/ e1 G) Z9 ]+ L* `3 M
- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化& @5 ~7 }- g$ S) ]6 I: |
. _% Y3 T n9 J4 Y- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1
1 M" `# S; h: j. F, w" i; O* O - //设置主从设备号
6 u6 n$ h) }. X! g" y1 I0 ^ - #define PROTOCOL_MAJOR 1. t% Z! `& \$ D7 H+ H
- #define PROTOCOL_MINOR 0
" q$ {7 N3 b5 N( }% }* p9 k
% \& G+ i% o4 Y( K! V6 }- + t5 Z8 Y1 y7 @
- }: w9 l7 h% P! r* L7 ]- //定义设备驱动的名字或设备节点的名字
: Z0 ^3 c+ \! {/ k9 D - #define DEVICE_NAME "protocol_driver"/ q D" v' o {# d0 m$ [2 B. E `9 v
- - P2 K+ }: ^/ R* N
% ?$ `# I( \: Q1 \7 X. T) q; A- //定义全局的循环队列作为数据缓冲区
) b; V D3 x) ?4 m' g - k_linkQueue queue;$ ]. ~; V4 G2 f9 v# `
0 r; W/ [4 v9 E4 K7 I- //寄存器地址映射全局变量' D: ^3 O; i# C* W
- unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器8 {7 S: t+ C8 M6 O0 _" N0 [ \' A% l
- unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器/ `! E# x! M8 s1 I7 j
- 9 b z/ O) Z% N* I
- //物理内存映射全局变量
3 w, ]2 J* ^! X9 x4 @/ _, | - volatile void *mem_base = NULL;
9 ~& X7 g- \5 c3 B - volatile unsigned char *cur_buf_ptr = NULL;
9 K3 i/ E- l, \" r - volatile unsigned char *data_ready_ptr = NULL;/ C4 C$ m& w: c1 b- _ h# T
; i! d9 i) G; h2 K& y- 5 Z G5 |: z8 S+ d8 u- x X
3 J! U! V0 a) s5 I& i3 H, X' A- //定义读数据等待队列头,IO阻塞- G) e% _5 U1 A' a) X$ x& A+ f' S
- DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);
( y+ {4 [; D: F - 2 E3 I8 R9 M9 I
- //定义原子变量
9 `% {5 O$ s5 y5 l - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备
! ~7 @/ X% R* j; r: ^/ m
4 l2 g0 J. @. }) W2 K# L' w+ E
4 R& c! }( P I( M6 O6 \9 X/ H- //定义设备类% V% I! r: F5 A t G9 |8 c
- static struct class *protocol_class;9 b7 l5 ^7 {8 L8 H
- struct cdev *protocol_cdev;; W% J4 D. i/ d- v/ K
- dev_t protocol_dev_no;
/ u# j: N7 R7 w+ H+ }' s% q3 Y
9 R; V6 l: a; w; U3 B3 A- /*定义tasklet和声明底半部函数并关联*/9 s" p4 N+ M$ l
- void read_data_tasklet(unsigned long);! F, u( E1 {4 y" r: x5 K6 g* ^, Z
3 x8 G4 W& V9 R: m# f a( ?- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
6 U4 c' A5 T: ? l - //将CHIPINT0_tasklet与read_data绑定,传入参数0' n7 c+ y8 m6 C7 |6 d6 S: F) P2 q7 V
0 q- ^4 G" r2 X; w9 ?9 m8 T" c0 d4 P0 L- /*中断处理底半部, 拷贝内存*/
) g7 j' k" l: C( z& ~2 D4 l - void read_data(unsigned long a)1 I* N9 ^) P1 @ v0 w
- {0 A' e" m% S$ }' V! A1 A9 P! g
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1
1 U9 _. `8 Z- w1 u1 _1 e - {) C( \; n; m+ h/ [ \
- read_quest = 0;
. P8 ]! s: t$ l& b1 {9 ~ - wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
4 V$ {1 I5 U7 W' |- M% G1 ^ - }
* ]! |2 a; |2 Y1 }2 d8 A - 7 y5 F: f. w) B8 Z) `+ Z
- }
4 y3 q3 F) W. r+ `/ d9 { - 7 w8 a- P- y. o9 G4 C$ P/ e
- /*中断处理顶半部*/
6 j" B4 g1 \& y/ x0 E8 \6 U - irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)
6 q; O( a! e6 D9 m* v1 D - {
6 M1 w; ]. _7 T. l - //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
2 [8 B& ^- \2 \ - volatile Buffer_Type *next_read;
$ E) d4 H, [4 h( o O - //如果DSP数据已经ready
2 I/ b8 i/ U# S. I - if(*(res_buff.cur_buffer->data_ready) == 1)
; S5 R% L% ^- } y9 w - {
K d! H, t& Z( H& Y, E( l - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer' H- X# F$ j! S8 Z" V0 Z: ?
- {& s; h7 j0 }& C* {3 B& ]- y
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer
+ r5 x+ E+ f) ?! q. r" g3 T/ L - //printk(KERN_ALERT"read ping\n");
' [8 p" \. O/ {5 V$ m - }0 u* ~ ~+ ?2 r
- else
/ o4 V' I7 o" e9 q- y4 p" o2 ] - {
* O5 {* I. j7 F7 u% E. z, [ - next_read = &res_buff.ping_buffer;//下一次中断读ping buffer
& A: W6 j0 E& C- D. j - //printk(KERN_ALERT"read pong\n");
2 I: x( |$ R! w) ~- R9 q - }1 k1 V" v, z% T
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer
3 L/ Z: Y. ~2 t8 [; e - //将数据插入链队列
j8 g( |; j. I* E( }' w# I/ x1 i - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);- t+ F" G7 G- J& F# i9 A
- //标识位都重置: N. }, I& ?7 a! }
- *(res_buff.cur_buffer->data_ready) = 0;
! c Q( a! x% D! J1 } - *(res_buff.cur_buffer->data_size) = 0;0 `% B6 c0 W# q8 v$ M
- res_buff.cur_buffer = next_read;
5 R- N5 F0 k& S9 S: O: \ c4 { - }: H( _% Q& k. h2 s$ O# d+ T( O
- //清楚中断标识6 ^' r8 a2 _# p9 S/ u: d" L
- *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status- s7 z* x) F; v7 v
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部
# v- _4 j1 Q: f. [" f) u, O - 3 R/ C/ J8 t) O$ F7 @
0 c0 }5 u. e& ?: z- return IRQ_HANDLED;( `/ f: i: }) S$ V _) e
- / k* D9 b! n+ H1 ?! a. t$ ]
- }
4 j, z: I! l+ B
* s, c6 h, v/ z7 X- d% R+ W- //文件打开函数8 C7 j W Z6 N) N$ _- t
- static int protocol_open(struct inode *inode, struct file *file)
+ {: r/ I3 t0 D4 i Q3 W/ [1 ] - {
5 ?9 T$ @+ S' V: k( K2 {% X# n - int result = 0;1 Q. ]4 ]' {& v7 w: E& x
- if(!atomic_dec_and_test(&dev_available))+ Y. f* r3 v$ A
- {
; k& [5 |# i! t u& p1 i0 ] - atomic_inc(&dev_available);( c" y' B, x$ ?3 P( P1 m% |
- return -EBUSY;//设备已经被打开
% k: g) j' W* O3 s8 |. f2 J - }
* ^+ N3 d+ x% ~5 B! @" i - printk (KERN_ALERT "\nprotrol driver open\n");4 [7 Z" {* D5 b: c1 T8 `
- return 0;
$ \$ r- a, r9 ]/ o `2 W - }
9 b' S/ v) A. J0 C
' k- x4 a, l, \' Q- //文件释放函数/ x# S3 `: B! k5 w8 p% r- ~* w- b
- static int protocol_release(struct inode *inode, struct file *filp)
/ H# o6 k% g& Q! z0 T( A - {: Y# W2 j( q V4 X! i. n& v( U
- atomic_inc(&dev_available);//释放设备,原子变量加1
& C2 ` ]& G2 A; p5 {% B$ a. U1 Y - printk (KERN_ALERT "device released\n");: }' J6 `/ U p* s1 I0 m2 E* R
- return 0;
7 }; P1 w& K9 C: q5 O - }5 L1 l+ `6 P; U5 H, N2 v: L4 E! S1 T
; z, s+ t g6 U- //文件读函数$ ^% p7 ?' D7 F/ c* X! O3 |$ u1 L( \
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)1 @ n4 W; v8 q" s
- {6 s, e1 q8 |6 |& ]
- int ret = 0; p E. c) r6 ]( U( R
- //定义等待队列+ f9 U; ^) d5 s) A# ]( z% T
- DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列
* n3 G6 K* _" d5 x - add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
% e* _7 y) I. V# x% {, p/ ^( h8 E - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
0 I. N# R# D& m7 y0 y( U - {
) t' S! R: Y9 G0 z0 F3 Q% w - //printk(KERN_ALERT"\nbuffer no data\n");
' W% G; T9 J2 j( C9 C - //如果是非阻塞方式读取,则直接跳出( x% o; ^$ \% X% { T
- if(filp->f_flags & O_NONBLOCK)4 Q1 n; u3 W! }; W' I! r; }( |
- {
+ x4 C2 }+ ?5 [" { - ret = -EAGAIN;
) G0 x+ M$ v% u# q - goto out;
6 N) o/ {1 U' ]+ D8 e$ C! V - }
7 _0 u: H# y9 K' M5 g- V: I- Q - //阻塞当前进程,放弃cpu资源; o3 s( h2 ?8 O7 q6 K. I% u& \
- read_quest = 1;
. `" Y" e% r, S4 S2 { - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠
5 Z- S' ^* v. y* H - schedule();//调度其他进程运行6 F" C1 S, Z3 H F. j; v
- if(signal_pending(current))
' b; f" S+ K. A - {
9 f, v: C2 D4 }& O& C - //如果是因为信号被唤醒,则返回到系统调用之前的地方
) a% G" R% Y7 W1 e" ~. X - ret = -ERESTARTSYS;7 A5 b6 X! |" T' Z: f6 |! L0 u/ E0 j" l
- goto out;
5 G! b; w; Y6 I% _0 m. E - }& O( m+ F$ _8 y5 ^, U8 `0 _3 N
- }4 V7 e& o, W* ]) |' }3 z
- //将数据拷贝到用户空间
, V9 A* w: f: E+ A: D5 s - ret = k_linkQueue_getData(&queue, dst);% h2 S5 T1 y0 ~$ N
- if(ret == 0)/ m+ u. E1 H# `
- {
% N& C, d+ {6 K* ^3 p' b% j - //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);7 N) {; Q0 i% f1 u7 a. {# l# x
- }0 l" X4 s1 v( X! t7 ]
- out:# l0 Y( V/ ~# ^
- remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列
/ S0 S9 {6 X. Y3 g, o4 J - set_current_state(TASK_RUNNING);//设置当前进程为运行状态# j0 [- l# i9 D; l$ B4 n* t
- return ret;3 F( \) o7 h5 X5 w# V* @
- }0 q8 B2 B) ?6 X7 t
u( G; P! s7 ` n/ o' e9 T- * b! O, v1 s" Q# b8 p$ n
- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)5 d/ Z M/ g, U! r. n
- {8 `' s8 I. w" n2 N
- return 0;
3 P* m8 \" P" E6 x0 U - }, M- d% i3 W" `9 G. q
- /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行- k$ ^* F$ q \) }+ o8 i+ f
- open()、release()、ioctl()协同调用时被调用*/ @/ G' k( p0 m, w' Y
- static const struct file_operations protocol_fops =: k% ?( v8 s1 K% y4 B6 L/ u# G
- {
: h0 T6 C! ^9 d; d; s+ `% d" V - .owner = THIS_MODULE,
, O$ T$ b0 v9 B7 i5 x6 ?* ~ - .open = protocol_open,) b6 J6 X5 n6 l7 C8 x9 q
- .release = protocol_release,
. h) E2 J, |/ s* u: G7 @7 S9 R - .read = protocol_read,
" s, B/ u" M# r+ j3 p - // .write = protocol_write,7 y- C1 x' l' ~+ i9 J* z/ U6 {
- .unlocked_ioctl=protocol_ioctl,
( V% n/ N, S) O! L# _7 j - };' Z0 n3 d- q* b7 z2 ]9 B5 }
- 0 t2 [ a& y6 P0 ]. O4 a* l( Z9 u
- /*设备驱动模块加载函数*/0 x4 S, B) [5 r# X( [; ?! \; f
- int __init protocol_init(void)
9 _# t9 O" f* |* z$ L - {
E- M- w* j n+ r" | - int ret = 0;
: K! R8 s( J% `: M/ B( D - int result = 0;$ w/ I+ j* w' c) c9 Q+ W# E+ v
- //申请注册设备号(动态)
2 J( k @& u# y8 Z) a: M - ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME);
* u* O1 t1 g) J z4 ?1 Z - if(ret < 0)
& ^7 g. z# r& {+ G h1 c% M- U - {5 K( @7 Z! D4 ]; W! v4 d7 X
- printk(KERN_EMERG "alloc_chrdev_region failed\n"); W' E0 O+ B1 ?2 w" j0 g7 u! L: l
- return 0;
+ J; L1 [+ j2 i' P( T - }
& F7 f) q% {- Z6 A, E - //分配cdev7 Q" v. G# h9 {7 U
- protocol_cdev = cdev_alloc();
$ h+ o! k" m2 u$ N$ f, l: J- s - if(protocol_cdev == NULL)4 h* g# a- Q' W! _# {1 V+ ~
- {1 j1 P3 `, r$ k. U
- printk(KERN_EMERG "Cannot alloc cdev\n");% J. n% q* V7 C, J
- return 0;
0 q# a6 W5 x; }6 M1 S1 f - }
) w2 ]3 H8 _, Z! z; @6 F) d - //初始化cdev. l! Q% a) V! Z6 C( d5 }% a
- cdev_init(protocol_cdev,&protocol_fops);$ R# f' _4 _) x
- protocol_cdev->owner=THIS_MODULE;
) N: D) i) i1 q- K - //注册cdev
( d0 R8 K3 _- X* n6 n3 r - cdev_add(protocol_cdev, protocol_dev_no, 1); ; Q3 j z, }/ G, N
- //创建一个类
& s2 I9 F2 s- l# B( K - protocol_class = class_create(THIS_MODULE, DEVICE_NAME);
- [- K8 g% R3 {9 L, t - //创建设备节点
* U0 Q( q. I& n% o" d5 [) Q* E - device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);
# [: m; g+ f( b! o$ D9 U- R8 V2 U - . ]2 g% h' h6 X- S/ N
- : Y6 H3 Y! I3 W5 z% B# `+ k- g
- //申请链式循环队列作为缓冲区DSP数据帧的缓冲区# c" ^4 |0 A/ b
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区) J" N5 p* w' J' d. `2 G1 t; f7 r8 O
- ! `8 x& ? R( D h. Y* M
- //映射ARM的核间通讯寄存器- \* R- ?- h2 c% Q, s
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
+ |; i' m# p! U3 \ - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);/ `: {, V. m; H _2 h
- //将物理地址映射到内核空间% q, O1 h8 Z& A8 v2 P+ Q" ]/ p
- mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);
$ g% ]% R8 Z0 Q, Z2 z+ L - //共享内存初始化
* A8 a$ {3 L# j5 C% W - SHM_ARM_Init((unsigned char *)mem_base);2 ]4 R+ z: G% j" i7 a4 l$ P
- /*申请中断*/
0 `* [; i4 V" X! _# B4 r$ e - - s' p' n* a$ V8 i( G
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);
5 x. I7 b/ Q& U+ {8 i: A8 O4 P z - if(result != 0)$ T8 Q {# A" U. A/ S
- {
5 |; J* a1 t/ ]8 U- X9 j7 A- n - if(result == -EINVAL)% G! Z* n( g/ g- G$ C
- {4 t G/ } `2 ~4 R
- printk(KERN_ALERT "irq request err:-EINVAL\n"); w& P3 h) W _; @2 H, ^7 s+ H/ ]( v
- }/ W1 F* Y) G }+ \# Q& V' {5 X
- else if(result == -EBUSY)" s8 b9 R" U) Z R( p
- {
) H7 V& ?8 Z0 f# N y; e - printk(KERN_ALERT "irq request err:--EBUSY\n");
* V+ K2 |' |% I( K1 A - } m5 l& S# V6 A8 I$ e( A
- else1 b/ j* g/ N7 w) ?" j
- {% D: S; F1 L3 `" t3 K0 [
- printk(KERN_ALERT "irq request err: unknown\n");
; M2 b( O# k" p. V6 f/ k - }
5 R* r6 o8 Y, C0 k - return result;
* ]# U) i, A0 D0 x2 L" B - }
* Z+ _- c! s9 M1 @& [6 ? - return 0;
& E; |# {" v0 T; h8 U5 p" s/ Q - }7 y+ V8 Y0 ^, A2 _7 h
6 w' a* v# V. a4 c- w z- /*设备驱动模块卸载函数*/4 o, ]! \. \4 n4 m4 G+ r X: q
- void __exit protocol_exit(void)9 @) _* s* y* U' `* {
- {; _7 H4 C3 j# }. g! x/ H d7 k. o
- /*释放中断*/! r& {! G) P2 R$ @4 U* m
- free_irq(IRQ_DA8XX_CHIPINT0, NULL);
1 Q0 G& i& F0 |* t* W: b - //释放帧缓冲的内存6 m1 j. k: T5 o* C3 t* T
- k_linkQueue_release(&queue);0 }3 c* H1 v: d) q5 q2 N/ Z0 Z1 a
- //释放寄存器映射8 ]* ~& k6 c! w. q" \, F
- iounmap(R_CHIPSIG);4 f8 b4 E# S2 u: ~4 T) v" _ o
- iounmap(R_CHIPSIG_CLR);' k; R+ I& F/ S5 \
- cdev_del(protocol_cdev); //删除cdev8 X \ G% b& [1 M7 d L$ l
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号
O; y- p& ~# L% L - device_destroy(protocol_class, protocol_dev_no); //销毁设备节点) P) Q) O, p9 L2 A9 E
- class_destroy(protocol_class); //销毁设备类
6 c4 o, i. Y; e. q5 R. X) V! B - printk(KERN_ALERT "exit success\n");
4 [5 Q$ X( {4 q/ C2 o/ W
0 `$ x* X9 T5 D: \( h9 s- }* s8 ^2 N7 N. P1 K9 G
- //驱动其他部分省略
复制代码 ( Z# b, |* K2 C. o* F
- b2 G" i$ B% A6 ]8 a$ g6 h
|