本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑 # a( Y4 ]# G3 c1 S% E
3 ]: V( H9 A: O' c+ u" p- m/ g项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略; I: R3 `$ U: P" |- h
& _ q6 J! J9 b1 u; E- //引入其他模块函数和变量
, N* M2 v& z- B1 \$ [2 N) _ - extern Ping_Pong_Buffer res_buff;, f7 g3 a! ]- n2 e; L9 }4 i
- . y8 X d; V6 f8 b! X
- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列
' I# U3 H8 I& P) l4 ~2 K% n7 _% V3 s- v - extern void k_linkQueue_release(linkQueue *queue);//释放链队列
. }/ Y6 `5 [+ e8 @/ D7 C' ? - extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据2 \( p+ k, e1 V2 s# d; L
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据
4 m* y+ X) B& ?" x& p7 U1 _% u - 3 {& r4 |2 G: v3 r! V1 U7 c
- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化
2 W N% t0 K! K- u" M, P, m - 8 C( K2 J+ X0 |
- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置19 g4 o' V/ s4 U- D+ K3 f
- //设置主从设备号
0 `: ~8 u/ B3 v# |; n - #define PROTOCOL_MAJOR 1% ?/ D$ r2 r: }. ?
- #define PROTOCOL_MINOR 0/ |8 I( `! b) M4 x( q8 R6 a
- * S# b" V3 T0 p
- 9 a# s' m7 O- q3 A* Z8 J
- / R2 D3 E% k; }. E& d+ k
- //定义设备驱动的名字或设备节点的名字
# R2 O- G) O3 V G- ^ C - #define DEVICE_NAME "protocol_driver"/ k0 q' v ~3 ~& M" H9 B+ p7 w- E4 ]
- " o0 y1 m4 C4 ~) h- M
- 6 M$ F4 }9 {* t$ y2 h
- //定义全局的循环队列作为数据缓冲区7 H P `$ w( Q! Y
- k_linkQueue queue; t# L8 ~1 `# O4 u% @2 b
6 Q- q/ r6 X" B7 W2 ~; n/ K, ^- //寄存器地址映射全局变量
* X8 g' h7 Z0 N, C- ~ - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器/ E) T+ W' q2 [9 W/ n
- unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器" B2 U+ x4 m! Z
1 t+ Z# o9 H1 D9 I! U- //物理内存映射全局变量
" |+ W8 z9 E' @+ P* X/ q - volatile void *mem_base = NULL;
7 r: j9 {# B0 }2 i2 s5 V - volatile unsigned char *cur_buf_ptr = NULL;
0 p: q! G' ?: D* D* H7 B - volatile unsigned char *data_ready_ptr = NULL;# D; S( v) d4 J
- 8 x6 x {* C/ Y3 y" Z! J
- 8 b; ^1 `3 H! j8 G! Q& }
& G6 z) N. ?, [1 g; a2 E9 R- //定义读数据等待队列头,IO阻塞
2 M$ R1 R: L+ l3 v/ ^& O3 | - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);
8 D c2 f. i& S! c' s* @ - 3 r0 U0 r* G; Y0 K4 d! A Q
- //定义原子变量
& S3 p5 v. A6 R - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备
7 @! {, |9 }( i- E; G" C" l
1 r. h) X) P$ D' x. \$ ^. B- 2 w0 }$ m/ M" K9 Z& k
- //定义设备类, Y' u0 u0 |& Z1 z
- static struct class *protocol_class;
, {0 O# _ s/ A& F% y; Q - struct cdev *protocol_cdev;9 e! D( f- w! R
- dev_t protocol_dev_no;
# T E. V$ P" a6 a% s
( r8 w# x. j8 s" I- h9 U; \2 Y- /*定义tasklet和声明底半部函数并关联*/5 N' @: X; \" z3 l: u
- void read_data_tasklet(unsigned long);6 z' A4 j9 m6 g4 V
- ) ] l) K( ? R; r, `$ j
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);+ \, E+ Z2 m6 w1 J. Q# e" }. D
- //将CHIPINT0_tasklet与read_data绑定,传入参数0# V9 C* H! n- Z% F
- " ^' h Q6 b1 ?% g: @: m* R: y
- /*中断处理底半部, 拷贝内存*/
& N5 N. J# O+ A2 ?; m! Z - void read_data(unsigned long a)* c" u2 ?2 F$ o# R
- {0 N8 G! a, g) N& L9 |1 `
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1
/ h" `, u) Q& V, V7 Q - {
; K6 p/ o" j. K( }5 w7 k( h - read_quest = 0; }8 c1 t. e; J4 ~& N/ v
- wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
O0 e0 m% x p- D% ]" v: P$ {. k2 g - }
* [- P) Q9 w4 [/ v# r: X5 f) G - g7 p, J/ z& d" a) d2 [
- }
1 L$ w/ S8 i, X- ^8 P - + b& [; a% }6 n5 p3 C) ^ }1 I
- /*中断处理顶半部*/* s% L. z, h ?3 r; V& d2 f
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)
, s3 x5 k3 _6 V' l - {
$ R' M9 e; I4 c3 L# n) D( G, Z - //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
j% h/ l- e" o - volatile Buffer_Type *next_read;0 b9 _ E, o! H. k9 L6 A+ [9 C5 J
- //如果DSP数据已经ready! T, |6 l, Y' j6 f$ X! W
- if(*(res_buff.cur_buffer->data_ready) == 1)0 I" u' q' v, i( N/ j
- {
/ j1 q q# l6 P D& Z- [4 Y - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer" E2 j8 w* `% M8 Q9 p* o0 [
- {) O# l8 y1 M. _4 S+ w
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer
: l' s5 M) U* V' y - //printk(KERN_ALERT"read ping\n");; f7 ]7 I0 ~' j5 [2 Y2 q5 G) G
- }
1 f0 p7 q) P! ~ - else
& `7 D5 ^( x# ~/ s+ E% O( C+ i - {$ m5 z& a" V( j- k0 z- B9 Q
- next_read = &res_buff.ping_buffer;//下一次中断读ping buffer
8 S2 ~. Z7 C$ g6 O - //printk(KERN_ALERT"read pong\n");
, z& H5 K* ]$ ? - }
& v1 l8 t% q7 S: y2 ? - *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer
0 E7 c2 W8 B# V& I - //将数据插入链队列
, L+ R' S V5 m" ?% | - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0); n" B B) G/ n% i6 K
- //标识位都重置
, Z6 Z% t3 w. _- b2 K4 N" Q - *(res_buff.cur_buffer->data_ready) = 0;" q' k6 T5 j: \8 P
- *(res_buff.cur_buffer->data_size) = 0;* W4 G" u) U. f% w6 \5 x" w
- res_buff.cur_buffer = next_read;2 e8 u( c6 `& g7 E/ t
- }& G# p. I5 S6 i$ y2 X( ~. a- \
- //清楚中断标识
" A( |3 ^* o3 f6 _1 j+ y( `/ O/ { - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status) {$ c1 w/ A9 E0 ]0 J6 |0 {0 w
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部
4 _% T- ]5 s8 W4 g5 m - * f& e" Z7 m$ }- k% P% ?
d! t+ X' H* x( `8 H- return IRQ_HANDLED;
4 B; }( x6 P: g - " Y1 x! {+ ?( d7 Q6 X( S1 o
- }& f, _* c& R5 S; {) l9 Y6 I
- , d0 Q9 R* d+ q! T
- //文件打开函数
8 G4 m, Y4 P% q8 @) y - static int protocol_open(struct inode *inode, struct file *file)$ M, Z3 z% @ ^0 a" D3 b( C
- {
5 k) o% [, s( ~) I - int result = 0;
5 u; \) G7 ] y: d2 T+ U) b, X - if(!atomic_dec_and_test(&dev_available))4 c9 R7 h+ j- ] A: U
- {: M7 l L1 n, p1 o
- atomic_inc(&dev_available);
+ o' G7 l( l c0 F - return -EBUSY;//设备已经被打开
. Y9 Q) p( i& K: d5 a5 h" {; X2 w - }6 p5 z( B" t. W& h$ p: }" g
- printk (KERN_ALERT "\nprotrol driver open\n"); }4 M6 T' |0 n2 S& B
- return 0;
' B$ H4 X" G! y5 ]' u9 r% z - }6 v$ \1 v! n3 W& E2 b
- + W% ?4 }) Z+ k0 h" K
- //文件释放函数5 ~% h m, M) B* e
- static int protocol_release(struct inode *inode, struct file *filp)
6 j( {3 h; i' w) d0 r% O - {4 B9 C( w2 |: U, b! _9 O$ C
- atomic_inc(&dev_available);//释放设备,原子变量加1
5 e# x: S- \8 v: z7 m - printk (KERN_ALERT "device released\n");# V, }& r' X* h
- return 0;! A$ E# M" U- y% N7 L
- }% }- u. f; d, V6 h, B! d
- ; F6 a: ?$ t" B. G9 i: }, p
- //文件读函数
1 [! u! _2 K! R - static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)
) i4 t( H8 J( J3 K; Q2 i( }- ] - {3 g1 e2 c+ a) }8 C! B& o
- int ret = 0;
; R! U- i' C: I: r1 Q( a" e6 P - //定义等待队列
# a4 x8 t; Q% _, o, ]. ?5 H - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列/ y( I1 T! D: v
- add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列4 r0 X6 K+ Z% r6 [' U5 _( s9 O9 o0 O$ O
- if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
; c, C) |. F$ {- u" @+ Y1 y" j, j3 D) V - {
: t7 S' i! l; J6 C8 P! O - //printk(KERN_ALERT"\nbuffer no data\n");
, r- C3 Q# D/ Y o0 M" { - //如果是非阻塞方式读取,则直接跳出
" s% V( `( R: Y/ d/ }' S0 r - if(filp->f_flags & O_NONBLOCK)/ f5 H+ z: |, B2 P; }5 c
- {
" w3 }1 @6 ]& J$ G - ret = -EAGAIN;3 o- ]5 `2 T3 _& y
- goto out;
# T% B& j" w+ Y: g - }5 W6 a' }" g' \( {8 j" _6 J; V z
- //阻塞当前进程,放弃cpu资源
7 }& V3 i7 W& J/ s3 a( Y1 b - read_quest = 1;
4 j3 x1 ^) r1 G7 A# j" h ? - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠2 x* n# O' k' `+ q7 M' Y$ S* U
- schedule();//调度其他进程运行4 R8 z( t1 `* Q. P) s1 @. Y3 X
- if(signal_pending(current))1 }; L9 P7 [$ f
- {
T0 ~. O6 r- q* E - //如果是因为信号被唤醒,则返回到系统调用之前的地方, P/ L2 G# z: x% p$ ?( Y& G
- ret = -ERESTARTSYS;5 V: u$ K/ X: p- q% i) z( D
- goto out;
3 ~' e: k9 J2 h2 U" [: X - }
/ i/ Y5 `; S7 W) ^ - }- ]$ @* M) ]6 u. _8 w1 F% J1 D
- //将数据拷贝到用户空间5 ^" w l3 R) W
- ret = k_linkQueue_getData(&queue, dst);
8 a! d7 \. [5 J7 J - if(ret == 0)! n: J7 G# G& J7 Q% A7 m
- {
! _ ?6 b' u9 ?! l - //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
, m* z" G; ]7 M5 L3 h$ R0 b - }
L5 [0 O! ~2 Q - out:" r% n5 I4 z3 j' o/ r" Z* ?% H
- remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列5 \* z$ K$ E T2 G( L
- set_current_state(TASK_RUNNING);//设置当前进程为运行状态
4 w8 X! u, @7 t* V) S4 O! ? - return ret;* L1 J/ |5 d7 l3 \9 b' v
- }, d/ Y) l, ~6 [$ q6 J! m! U
- # U& R. w5 o8 i; d
- " X* L- P8 X9 v$ y
- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)
4 D, c. y+ S1 r - {
: ?& r+ O, ~' w. t% L - return 0;( q& R v3 [! B$ \5 L& w3 F( P6 |$ \
- }
9 { j' n$ L/ Z - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行$ ^% u, I8 e5 G( q/ {" H
- open()、release()、ioctl()协同调用时被调用*/7 U% `0 M4 x# X
- static const struct file_operations protocol_fops =- H0 h" b# Z9 Y& S
- {6 p' X. s. R, K! ~+ R) g, o
- .owner = THIS_MODULE,
0 E8 ?+ B. ]% C - .open = protocol_open,/ C7 m7 Y8 |; u5 x* Z) V
- .release = protocol_release,+ N' v% c% O8 q0 g$ Z$ O
- .read = protocol_read,
W: {- V Z" o& p5 T4 `9 B - // .write = protocol_write,9 J( d( K+ h5 ~
- .unlocked_ioctl=protocol_ioctl, t [& s& Y: ]
- };
4 v: b: \0 Z% x1 a
2 N/ M1 d5 `6 T0 f% \3 ]- h- /*设备驱动模块加载函数*/2 r" b }$ U7 o; X. I2 n
- int __init protocol_init(void); E0 ~# Q+ c) @2 v
- {
4 I, h: M: g) j6 y - int ret = 0;
" Z& V+ }+ H5 Y6 s9 Q4 ^4 [1 _1 @9 d - int result = 0;
# y1 {% a- Q* B - //申请注册设备号(动态)
2 o) w2 J& q+ P& _% y - ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME);
) {' t- A) D J( N$ Z2 u7 Q" L - if(ret < 0), U( K0 n3 y# z
- {
8 j) K( X! x5 b% _/ @# k+ o' I; A - printk(KERN_EMERG "alloc_chrdev_region failed\n");- R5 G' Y* z7 V) x3 b" M- {
- return 0;
, x9 @* U# i0 o7 x: X+ | - }* ^& ^; \- N) J, I3 L8 x
- //分配cdev9 j, d5 r) l" H3 ]
- protocol_cdev = cdev_alloc();
& Y3 e$ J# \ `1 X+ Z - if(protocol_cdev == NULL)6 H; u' }6 _3 I1 X4 Q
- {
& D. f+ E3 W7 P - printk(KERN_EMERG "Cannot alloc cdev\n");
/ p' p) f" j5 D+ ^8 Y3 w - return 0;# D, h' E4 V, e% \7 @$ O6 M
- }* X% k# g) Z4 B
- //初始化cdev
" C6 ?, L L0 J$ }& y - cdev_init(protocol_cdev,&protocol_fops);: i1 @5 ]1 u0 I' h! M: h+ G, g. h
- protocol_cdev->owner=THIS_MODULE;
0 t) ^8 ~, h! \ I) J0 z; G' W - //注册cdev- m3 g! H3 D- {; i. e6 W( P/ k
- cdev_add(protocol_cdev, protocol_dev_no, 1);
( l- x; n9 E1 C. S1 K; | - //创建一个类- H( m' w! r$ K$ ^2 ]$ _1 P
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);# a0 l# T* W9 u$ l9 _
- //创建设备节点
. x! k" q4 A" Y0 X- Z - device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME); I% p/ ^' `8 T1 P6 j+ u
- a) E& B. `1 a+ [6 y
- ( |' B5 t u8 k8 _) J/ v
- //申请链式循环队列作为缓冲区DSP数据帧的缓冲区5 T! U0 `3 J# O( }
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区
3 E9 B" Z$ `" m( l1 U. M! r
# N, @, k& n" z; N- //映射ARM的核间通讯寄存器( x4 R) u/ F" V& o2 G$ z( l
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4); \. v% q9 H) p6 @) f
- R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);$ B! Y3 C; ? b/ b" C+ n
- //将物理地址映射到内核空间/ S2 N% R6 Y( Y( v1 O9 [* H
- mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);4 u4 W! [2 R. R ~$ `1 Z* N
- //共享内存初始化
0 e4 _6 I* W8 @ - SHM_ARM_Init((unsigned char *)mem_base);
8 n8 h$ m0 n) @% i: D+ M. a - /*申请中断*/2 G4 J4 |( y0 x( {
2 y6 P7 M* }2 G8 V& [- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);
1 d) Z& Z, l' T" X( ?7 v7 u - if(result != 0)+ o' n: x# a9 ]/ h
- {# n& D2 }1 d+ [1 i. J. y
- if(result == -EINVAL)8 K n- C' i; B$ C9 V! @6 p& U
- {7 n: h% k8 d% a" J0 K
- printk(KERN_ALERT "irq request err:-EINVAL\n");6 `8 E7 a Y: ~ v
- }
7 V! `5 }* |& i# C9 b - else if(result == -EBUSY)
) D' H& r1 ~3 i/ C6 Z. y; ^ - {
9 S+ p0 P- J, e1 m& r% _& @ - printk(KERN_ALERT "irq request err:--EBUSY\n");: I- }. ?5 y: N6 R j0 D9 K
- }' C. s. ^1 a) ]- S5 Z7 B
- else
' e5 o' c! Y" {( L2 U - {
. {, Q1 U" N9 g# \/ Q& r4 J) d) f: q - printk(KERN_ALERT "irq request err: unknown\n");0 Q- u: c8 i5 w9 K! v: {2 D7 q
- }. v, { E; w9 ~1 t% | {
- return result; i3 {4 C. i2 t9 h5 G
- }9 T8 d/ ]8 \7 Y& X- Z& M
- return 0;
* I- L+ M+ [! U2 O$ S - }
3 o# Z2 R7 H+ O& P
0 ]8 Y+ \) A2 M+ K) u- /*设备驱动模块卸载函数*/( m6 [0 B/ n. h& g/ w; t0 \' E
- void __exit protocol_exit(void)
4 ]- P7 B* ^2 m - {
% A$ k/ U- u# ?3 e - /*释放中断*/
& h7 ~! b+ D6 s* {! e - free_irq(IRQ_DA8XX_CHIPINT0, NULL);: I7 m0 H. i0 T: w( S2 o5 _
- //释放帧缓冲的内存
+ S0 Y) q; z) S: d - k_linkQueue_release(&queue);
" z* J N9 `8 V - //释放寄存器映射+ a" ^8 Z9 E! w/ f% u
- iounmap(R_CHIPSIG);/ V1 B' [& A+ T- b
- iounmap(R_CHIPSIG_CLR);, w" b9 Q& z/ |6 r N
- cdev_del(protocol_cdev); //删除cdev' d# P. r7 h$ j* u/ x* ?
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号- h; ]9 U; T ` j( P- c
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
6 ^6 h+ h% F& `3 X! O5 q - class_destroy(protocol_class); //销毁设备类
& ~/ o. a9 n& A5 O - printk(KERN_ALERT "exit success\n");
( k5 S' M+ M, y! C. n
; c$ d: n& d! Y$ x- }
9 a1 H+ U3 e1 E, v. u9 Q - //驱动其他部分省略
复制代码
8 C5 t5 s& L8 ~' _1 [' q3 q! n, B; n- A- x5 l
|