本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑 / s, O, K! W/ t# M
7 \% h* \- I% k7 S4 q$ m6 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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略
7 w0 n( u3 j0 V) A/ @% a0 S, @4 ]+ a - 6 H5 e, ^2 A9 l& V! Y
- //引入其他模块函数和变量' u& }$ o3 Y" T/ |; m( ?4 t
- extern Ping_Pong_Buffer res_buff;/ N" a c2 ~ s6 J8 w
! Z2 n4 A" O7 B8 \9 p; Z- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列+ ? o$ L& N8 u
- extern void k_linkQueue_release(linkQueue *queue);//释放链队列, B4 x2 U, f2 b
- extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据
2 d% U0 o9 v) y: ]# w5 O - extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据) V$ V& {, h( ~$ _' U
8 x- Q& ~6 T( W5 P6 a- O: b: ^1 W- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化" M" a; z$ u1 I2 o+ V4 Y; K
- 7 O9 T; W/ x2 { v
- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1
5 M: `5 y! D6 ?# s - //设置主从设备号
% |3 V* B% o+ B$ M5 f - #define PROTOCOL_MAJOR 1' I' R- V) r/ t: @, V% q
- #define PROTOCOL_MINOR 0 @5 T3 B5 O* K3 E( j: \, K5 T
- 9 q; W x2 x& S
! o; q, F: {8 G0 u E
* Z9 k' p. q$ d3 c- //定义设备驱动的名字或设备节点的名字* t! Y9 f; F; j5 h
- #define DEVICE_NAME "protocol_driver"
8 j1 @7 g [# U U
B' a7 |% E- y+ H. C* a: L+ c# `
# h7 y) |( T, ]/ F( S2 H- //定义全局的循环队列作为数据缓冲区
! S% y6 m! P z( X% U2 v - k_linkQueue queue;
. K6 W8 m% E0 r, N - 5 `" f; G5 l. i+ A4 d( K5 z
- //寄存器地址映射全局变量
( \. z( S# Z5 c( D$ k$ q) y - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器4 G+ L5 W- u3 _: q# w E
- unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器
, ?& x. N& o+ F4 W8 ]3 Z
. s. T* }! Y: |. B* F- //物理内存映射全局变量( h. j9 S t" A2 D7 N( R# a
- volatile void *mem_base = NULL;! r1 ^" p" Z& R
- volatile unsigned char *cur_buf_ptr = NULL;/ H* Z% V4 `4 Z( n1 [% D
- volatile unsigned char *data_ready_ptr = NULL;+ p% r; g4 r5 ]: a/ n. m# ]
; F1 x% d6 e% h; {6 i: ^$ E5 a, T3 V& n
5 R9 g9 e. r, b2 x. C
; o! p- f( g. U' }- //定义读数据等待队列头,IO阻塞
4 L9 t4 J( X Y/ J: V - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);% f, B, J/ O9 H9 s
- - [( g% k) h! `, H" j
- //定义原子变量
* z7 p3 Y# B e5 s$ r8 E - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备, j3 e h3 a H; M) h
- . n1 n" b* i# X6 `: F/ {" O
) f" A d4 g% c3 b- //定义设备类; x% o, s' }$ h; w+ ?- a
- static struct class *protocol_class;; [3 i" F, A/ v9 F6 c- T
- struct cdev *protocol_cdev;% k( Q/ G9 {, n! I M$ q; |: H9 j
- dev_t protocol_dev_no;
3 ]& j* G- R2 \ v! F, v7 w" ~
0 q4 ]5 ~2 p+ L/ Y# T0 B. U- /*定义tasklet和声明底半部函数并关联*/
. K# r! U5 j. x! t/ m! ?) l% Q - void read_data_tasklet(unsigned long);) s. [# `$ ?! s% S* X0 E/ ~
- 9 f t' m, ^* w
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
6 `7 H. C" o! H1 L! Q - //将CHIPINT0_tasklet与read_data绑定,传入参数0
) D5 w1 M8 F7 u I
; A+ J/ P2 ]& k/ w* s: W5 W; M% }- /*中断处理底半部, 拷贝内存*/0 V6 u+ v1 c* z( `1 J
- void read_data(unsigned long a)
3 N" ~2 u6 z3 D$ [, Q# u - {# d4 d$ r7 v& V$ x6 ~5 o7 W
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为19 P* @/ Z E5 ^
- {
# ?1 u5 Y9 v" L! T8 ?$ w7 F" ~ - read_quest = 0;
: q# w0 S7 p* z" B - wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
( a, u. z/ Q; ]6 J1 W- h- p5 Q3 w - }1 p& u7 O; H" i5 m
- ) B. R7 ] N' a2 b
- }
3 g1 W# H( u8 _4 o - * _0 m. }! ]' S5 P) R0 i
- /*中断处理顶半部*/; {5 O p' P9 q& O' {+ S
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)
0 |8 M, K9 O9 ^0 R: ` - {7 b5 h5 p& J5 n+ ]2 C! O8 i' j
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
- K6 V9 G, `6 @5 k' h/ ?" i - volatile Buffer_Type *next_read;
8 o7 ^. t' k! r+ I; g% c! p - //如果DSP数据已经ready5 j6 R+ ]& Q5 O% o" j" `
- if(*(res_buff.cur_buffer->data_ready) == 1)& \' @6 f: u9 b. w# A: C
- {
' a) n4 `: h# K) |1 F7 R3 |2 } - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer. k4 q6 ^, o' }# L* A+ m* w& K2 _
- {
* e( l0 u3 h# v6 x - next_read = &res_buff.pong_buffer;//下一次中断读pong buffer' f* S! o* \- x
- //printk(KERN_ALERT"read ping\n");
& w7 k$ F k5 l/ i - }
" R1 M# M/ x, \( e" b! J - else- N/ ^3 Z# B0 u1 P3 Y ^# I2 b
- {
' R+ K: B, C2 d; u' M" Y" g% f - next_read = &res_buff.ping_buffer;//下一次中断读ping buffer
! A/ Y& p% U y - //printk(KERN_ALERT"read pong\n");) y7 o( o3 k( S, Q+ n( |, C+ u. @
- }
5 B d' `( j' Z/ G7 l3 W - *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer6 {, `4 w' W' n4 W) U$ r' {
- //将数据插入链队列
/ T) p8 f0 r2 f) x) i& @; `9 \ - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);
F! n7 F" R) u0 Q - //标识位都重置
/ I3 ~: @: i- t6 o8 _4 Z1 v( N( V - *(res_buff.cur_buffer->data_ready) = 0;
! G0 v: j' x$ {3 K - *(res_buff.cur_buffer->data_size) = 0;7 v; H F n8 @; p' V2 Y2 T
- res_buff.cur_buffer = next_read;
: s8 e1 B, @: C* I8 O - }( g: F) n& Y/ X8 z
- //清楚中断标识
* m8 c% ?' W' v5 i - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status5 v$ h; F. v' L( l
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部 # e+ G* f8 s! P% @, |$ v
- ; e i" X4 [+ m" |* K; }
% k! G, P- m/ A, a. y8 [/ o- return IRQ_HANDLED;
4 M9 s- C$ \; q5 O - ; [9 `! J4 r o1 a1 q
- }
" `* M* d/ ?' K: g% i
$ E: z3 t( p6 {( ~- V- //文件打开函数
$ ] ~% V' c! }( n - static int protocol_open(struct inode *inode, struct file *file)" ?4 A# S9 \! @$ s& f" Z O
- {
4 w- |: Y. B/ H2 N - int result = 0;
* c8 F+ Y& Y2 P. P - if(!atomic_dec_and_test(&dev_available)), S% o- {3 `( m- `% M
- {
. H* j3 u5 o1 g5 e - atomic_inc(&dev_available);. t% C5 s0 d; Y& w7 T3 J2 M
- return -EBUSY;//设备已经被打开
' D% \' V! j1 Z- i3 J - }2 n* p. U$ y- |; H d
- printk (KERN_ALERT "\nprotrol driver open\n");% _# E4 A D' t& U T
- return 0;, i! O) g, E5 S) g. e" y0 z) L6 ^8 b' \
- }
* Z H0 H: ] J N3 H - + f0 u9 u- J. B1 K0 B) Z
- //文件释放函数
' U+ f; L9 C9 j5 z- x - static int protocol_release(struct inode *inode, struct file *filp)/ e/ p: w6 U+ f# l: R
- {
; |2 u2 g4 f6 S) z, m - atomic_inc(&dev_available);//释放设备,原子变量加1
% B6 z1 D* r" \# b* n - printk (KERN_ALERT "device released\n");
' J0 H( ]7 ^. s- _" d6 r& r - return 0;
* X Z% }8 m3 B( I" y5 t - }
8 d% |* m" q' u j6 ^8 w6 M
/ n2 v9 X9 X/ ~7 q- z- //文件读函数
0 i7 E" N2 T2 I8 p: P- ?0 I7 P n - static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)7 d! L: W0 O( ^2 j( m
- {+ W: ]0 ]+ D! N$ ^, n
- int ret = 0;, f; G8 m4 S% D0 l3 k! p
- //定义等待队列
' Y: |$ |, V; l: h, z# w; [ - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列3 v+ q! x! S5 y2 A) S
- add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列; V* _) C. X2 u2 H
- if(queue.remainNumber == queue.blockNumber)//当前buffer没数据9 m" q5 ?% _+ C9 Q
- {
3 Q- [! g; l& |, X. H, I* J6 _ - //printk(KERN_ALERT"\nbuffer no data\n");
2 E/ f; E+ ~; D/ F - //如果是非阻塞方式读取,则直接跳出
; Q J3 C. [2 s- ^" h" E - if(filp->f_flags & O_NONBLOCK)
7 K* h1 j g% h - {
! k/ S) ^7 c5 ~0 K+ R* _ - ret = -EAGAIN;/ J1 G2 L1 g v
- goto out;; R# j, U/ o" f
- }& G# N0 ~- Y, o/ a
- //阻塞当前进程,放弃cpu资源
" E8 [3 k2 }+ |# C" q - read_quest = 1;
/ a, ? e' ^: m2 `& K - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠- D1 Z$ F5 F2 c3 O. @+ x5 R
- schedule();//调度其他进程运行
7 K+ L3 }) b0 ^ b. } - if(signal_pending(current)), J) U9 p* k1 e/ B# p6 H
- {
7 o: [/ W2 Y& g - //如果是因为信号被唤醒,则返回到系统调用之前的地方
+ s: B2 v( z- J- T - ret = -ERESTARTSYS;
8 p5 S+ C/ u& o) t* g' y, u - goto out;
: r- C; l3 g1 O1 R7 H) _ - }
& b$ Q" x7 }% s! ~" c0 [* a - }
/ l z4 V$ r }9 b- V7 a( `) i - //将数据拷贝到用户空间4 ~2 N/ F/ R; a1 u& Z: l( }" J
- ret = k_linkQueue_getData(&queue, dst);
" H1 V9 q/ V5 ]8 t. m - if(ret == 0)( _% u3 b. K+ K8 Z4 m: i: h
- {0 o; |$ ?3 B* c3 l3 j
- //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);2 V( v3 S1 j4 N/ _$ O
- }1 w9 `* e- T" r% K6 F' f$ b* w/ u5 ~7 v
- out:
. X0 J5 ~, t1 k O0 {1 V6 v - remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列+ B0 C3 s. U7 B6 h& k7 ?- F
- set_current_state(TASK_RUNNING);//设置当前进程为运行状态; j4 ?1 U: y$ [" u0 h) S
- return ret;+ A/ R. |7 m* i z2 `% V
- }' K/ _! e: ~+ }7 X
+ j* P9 m: }9 {& J! G- + q$ w8 w# \( @0 Z
- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value). v# J, k; x7 a% E- N
- {5 U l3 J: F! b9 h4 u) o/ U
- return 0;- R/ F6 S7 }1 R; m* x
- }# a* i' q7 `) A- f! q
- /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行" o+ d+ Q: k- c/ `# R0 E" w
- open()、release()、ioctl()协同调用时被调用*/
: D& _" W8 J$ \. E$ _: @ - static const struct file_operations protocol_fops =
0 I) t' H+ Z" _ - {, R( I6 F1 s1 x* t* F, B
- .owner = THIS_MODULE,( n) S& d6 F8 _) N. G
- .open = protocol_open,' {8 K1 ?# ^/ v" n) U3 Q4 n
- .release = protocol_release,# Z' X0 o5 s: ^" t# V' w8 T
- .read = protocol_read,% E* z5 T3 u! @6 F4 G7 b
- // .write = protocol_write,/ p% _6 N, {0 l0 X; Z
- .unlocked_ioctl=protocol_ioctl,
) T2 r& G. O. S. h# S$ u2 A" L/ s - };5 C) y; @- c: u, M- ]! |2 a
3 ^) K2 t9 L4 j% d/ \4 {- /*设备驱动模块加载函数*/ a" m( ]( E p" N' F
- int __init protocol_init(void)% Y# ]/ p% m7 T( e7 z- F. T' j7 J
- {6 {0 ~6 d; v( }# S- I, T3 Y& Q/ p
- int ret = 0;
4 ?: J* K; E i2 t4 ? - int result = 0;; h& A& B3 T' l; V' H# `7 L
- //申请注册设备号(动态): h3 j4 Y, V! k( y
- ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME);
- C0 m N7 \8 N' J, v - if(ret < 0)
$ M$ O9 R& [; }! i$ _6 @ - {$ ?' D. d# [; Y N$ q
- printk(KERN_EMERG "alloc_chrdev_region failed\n");
6 H& U2 I# S0 l) N- r - return 0;
@- B8 k. _" x4 V6 A; O - } B7 W& _4 S) E' d
- //分配cdev
4 H5 h- F9 p7 M# |4 w) x - protocol_cdev = cdev_alloc();
! K" ^- ?' W5 ?& ^+ b p/ f - if(protocol_cdev == NULL)
( Q: i3 @& ?* [6 C2 L( r - {- A# j: @1 _# }! u
- printk(KERN_EMERG "Cannot alloc cdev\n");7 a; [9 p6 Y; D p
- return 0;
1 D! @& ~9 ]0 l - }) u3 H; k6 Z9 L# [) g j
- //初始化cdev3 L- c; H& X- d1 h4 P; b
- cdev_init(protocol_cdev,&protocol_fops);' {3 [% _7 m: u
- protocol_cdev->owner=THIS_MODULE;
' W$ U: p8 V: q. @7 O - //注册cdev
q8 W0 @6 M5 L - cdev_add(protocol_cdev, protocol_dev_no, 1);
1 p( N# [- g# d/ S - //创建一个类4 B6 R$ s, ]8 Y5 Y1 Q# w
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);4 ]0 {9 f3 C( V9 [( F, P
- //创建设备节点" {; W7 y& i7 [% k( b$ V& n
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);6 A- s) Q' u) m. U7 {" h1 G# c
-
4 d2 j0 q1 ~4 b* r: C/ ]: V -
2 s- L. U2 i/ @/ r5 x3 R - //申请链式循环队列作为缓冲区DSP数据帧的缓冲区5 Z8 s# K+ D+ ]+ q9 L( }
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区
6 B% K. l( j% F& [# I, U# I - " B! ~$ Q$ u1 ~( f( r
- //映射ARM的核间通讯寄存器& N6 L. W/ {0 b; Y( Q3 b7 [
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
5 p9 M' z8 K2 p& S q - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);& g' T9 a5 E3 J A
- //将物理地址映射到内核空间0 I2 ?* `* `4 ~* q+ r5 y
- mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE); [6 m+ e& Y4 r+ o1 V
- //共享内存初始化" P9 ?1 w% D& }$ G! i2 J: V
- SHM_ARM_Init((unsigned char *)mem_base);
}0 ?* F$ n1 @6 u9 R+ v- p - /*申请中断*/
( B" N. _- h# [# z# \ - 4 _8 J- n/ B4 [
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);
& {; w( r2 h- E - if(result != 0)2 b' E3 Z. m9 l j" F
- {7 i- |! `. y: M* i3 X
- if(result == -EINVAL)
. g- f5 n# W$ e1 m - {0 [8 {+ L9 S* X, _6 I
- printk(KERN_ALERT "irq request err:-EINVAL\n");7 `3 j& P) }" [3 \3 C
- }
& S/ @2 H7 Q$ W8 n7 S" ] - else if(result == -EBUSY)
2 {# P! V" j7 M8 f9 M. F - {, V& L5 |- R; @
- printk(KERN_ALERT "irq request err:--EBUSY\n");
" w# ~7 [/ X) z+ h( M2 d - }
" q7 ]" ] p. \2 o# j - else0 _& b, J. n0 g, ^2 t
- {
0 G$ X2 H: n+ n" g" L- r - printk(KERN_ALERT "irq request err: unknown\n");4 h4 U" T L, p% r( N
- }; d" g, ?# _, W& ^+ @ y6 O0 K
- return result;
# g# A, ?6 y/ @9 _ - }
* k3 e1 m' }5 I' v. t - return 0;) ]* }; n9 W7 X) k' _2 i& s
- }6 x) A' j, O. i; M: s, A
9 S$ M; }8 C) v* U8 j7 T- /*设备驱动模块卸载函数*/' w" c3 r- C- J; z: z
- void __exit protocol_exit(void)- e9 P3 f& [2 g: e5 s' g. [
- {
+ f: _& ^: Y* E! w N. M3 t - /*释放中断*// W4 w* w0 Q& X( J% ]. Y
- free_irq(IRQ_DA8XX_CHIPINT0, NULL);
9 O* V& v) q9 s* d; T& \ - //释放帧缓冲的内存& [3 ], F, I5 S* [
- k_linkQueue_release(&queue);. j/ }3 l- f) u! Y. f/ @
- //释放寄存器映射3 z7 s+ F1 r3 C% l$ K% W
- iounmap(R_CHIPSIG);
3 |8 \ C& B! \& n) j a- w3 { - iounmap(R_CHIPSIG_CLR);
; J1 D1 P; C% E4 ?" V - cdev_del(protocol_cdev); //删除cdev. p% V$ A* c) Q8 b# [
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号+ q$ V$ V* U$ j0 t+ [' l; X; f. \! y
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点6 x" M% ^ X1 z. j; [6 [( i
- class_destroy(protocol_class); //销毁设备类
( ]& H; C# q: b) ]1 l4 X m - printk(KERN_ALERT "exit success\n");
9 T) ?$ K6 \5 L
* Q& h% x! j( L% j- }- z8 d! l7 a! m4 l' q9 ]
- //驱动其他部分省略
复制代码 - m4 w6 N& G7 V2 H, Q9 r
( M, ~4 D: }& K$ }" J3 K |