本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑 3 ?" R1 j+ r4 Y- B) O
3 H! g2 d7 x' W5 F项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略) {6 I. c o7 `
- % D/ F: k# N8 f& {
- //引入其他模块函数和变量- b2 H2 x: b" g4 l6 F
- extern Ping_Pong_Buffer res_buff;8 t/ ]9 Z0 k) Z
% f y; n, ]! \- R* n0 F3 N) @& f- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列* B3 V0 g4 {/ N) t! _" U- {
- extern void k_linkQueue_release(linkQueue *queue);//释放链队列
/ N7 M% i/ O# x9 @4 N$ _ - extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据$ |# q4 t$ ~7 d* M
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据
: B. V5 @% t# M' b/ W: h' v
- J& U& J* L$ J1 s6 Z8 s- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化3 O4 T) g, u3 H6 \# e5 K" S7 P
) H8 L% n! j# U5 D- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置18 N0 h6 l: Z& G: W. Q+ d Q b
- //设置主从设备号' k, x& x/ w; N( `8 @& o2 G
- #define PROTOCOL_MAJOR 1% D- P7 H. [. o4 {* s4 s
- #define PROTOCOL_MINOR 0
8 j5 j# S' Y+ R6 y; a5 z4 I - 7 _2 D7 H; W3 Z; T# ^
2 j, ?, v( n5 H9 ]9 A) K0 g+ L- 9 X L& L0 q. @
- //定义设备驱动的名字或设备节点的名字
# \3 e% Q6 `" P; q7 l; j" V% t - #define DEVICE_NAME "protocol_driver"$ w3 P5 O( @7 G. K! l5 z% A, a
6 R% i6 x6 S! V: s( k- 9 t, s/ k6 I- h: K
- //定义全局的循环队列作为数据缓冲区: D8 D4 t6 S2 s
- k_linkQueue queue;
x/ l c: [2 u7 @1 X/ ^ - , t& f1 {4 P1 `' i
- //寄存器地址映射全局变量/ C3 k+ G0 a u; v% J) n9 a1 k7 I
- unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器
( t" H8 S) {; T# r8 C9 f - unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器! Q1 e) X. X; K# n0 @5 Y
- 3 c+ S6 U% p$ P0 M9 @. F
- //物理内存映射全局变量! l6 b2 Q K+ C* U- A* W& q
- volatile void *mem_base = NULL;
1 g; K3 g: }* n2 Y - volatile unsigned char *cur_buf_ptr = NULL;. M) E. {) n. y( _- B
- volatile unsigned char *data_ready_ptr = NULL;, q/ R( z4 _/ B9 O( z) w. G% p+ Z
- , s5 @9 W f0 A" H/ x) H. t
3 T6 r0 t7 s7 S* O5 f( w" X- & C9 G! U. k& ?. k* d) n0 T# `+ V
- //定义读数据等待队列头,IO阻塞
' Z0 |2 U- I) Z9 x/ l1 G - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);
/ M1 S! `% y8 |( h" G; }$ F4 F - % w0 h! R( n+ Z0 p
- //定义原子变量- @7 I3 \; p1 q- |/ k
- static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备
/ T f T1 o/ Y, m; T5 X. z - 7 q9 H1 U( V6 ^0 Z
. l0 a- [+ C& Y" W* q- //定义设备类
7 t$ x7 R4 |1 }3 F- D' W( k - static struct class *protocol_class;9 F" D6 k* x; c4 {: P D
- struct cdev *protocol_cdev;& |4 w6 o" p5 T7 W1 @
- dev_t protocol_dev_no;
% G& S! U5 N) s1 V
7 B6 b9 X1 q9 z- /*定义tasklet和声明底半部函数并关联*/
7 ^) P; ^: d, C7 C/ f - void read_data_tasklet(unsigned long);
. ~9 V" m5 o, U0 O. R7 ^, o+ @9 y
0 O& e( d6 j9 c/ c' I3 [- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
1 Z5 y6 E* K: U - //将CHIPINT0_tasklet与read_data绑定,传入参数0
/ Z+ ]6 e& s8 m - 0 t" `- t; k" z8 W$ ]9 V0 B
- /*中断处理底半部, 拷贝内存*/
5 J( i# r/ c' F. Q7 v, o - void read_data(unsigned long a)
; w- n: M$ e3 K6 z5 _8 Q3 p - {3 z% a4 {5 y2 K
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1
: y+ J$ `6 P3 e+ G# P% i% _# q - {
) O' K8 L: J: A. g - read_quest = 0;
2 G) X" P: A' N - wake_up_interruptible(&wait_queue_head);//唤醒读等待队列2 J+ |! Z' A7 w% }' c; T
- }" N+ `1 H& L E& t. M
- : d- X0 V+ @5 W& Y2 S4 q+ n
- }7 o& @2 a7 |8 b( M% b6 k
- ; m1 |3 b C' N( S
- /*中断处理顶半部*// d+ ?9 B" q" v% j1 I* y9 i! M' [
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)
, O0 x4 s' Q2 Y0 E! M0 ~ - {0 M4 _" [+ C, W* V! L7 E: C( ~
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
; k A6 y4 L0 F+ c) P* ` - volatile Buffer_Type *next_read;/ r, b4 l9 a W0 _ ?9 L0 c' y
- //如果DSP数据已经ready9 U& t6 |" q4 I z% j
- if(*(res_buff.cur_buffer->data_ready) == 1)
6 T1 H$ f1 Q$ k% M/ ` - {" d: ~. w! B' N5 S
- if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer0 N& V5 E( z: H8 v1 n
- {5 P$ A1 I& d. E3 I
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer
, s) {) J8 p3 ]7 R5 D2 W! W6 F$ K - //printk(KERN_ALERT"read ping\n");
6 V5 u3 {, s: h/ i' ^ - }
) P- k- J. e0 k - else
8 A# a$ a% M n& J% _ - {
, H2 d' K B$ F7 P, |( y - next_read = &res_buff.ping_buffer;//下一次中断读ping buffer
! v- @+ a+ S6 V& v - //printk(KERN_ALERT"read pong\n");9 s6 k3 g3 d6 Y! F8 p
- }' d) d' G9 ?6 s4 w# u
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer
2 E! U7 d7 M$ Q4 T* ^3 _* O4 h - //将数据插入链队列3 C% i- G3 G$ x- n+ z3 ^6 ?
- k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);$ B" G* R% \. S. X( Q! j3 |$ `% d- ^
- //标识位都重置
+ M; ]5 K, u' \, m& s" I/ k - *(res_buff.cur_buffer->data_ready) = 0;
! q0 y+ o. B) E* a- ]* V - *(res_buff.cur_buffer->data_size) = 0;
( }% i- W6 m3 `+ o' ]- d& C - res_buff.cur_buffer = next_read;
* a/ e9 Q8 \8 Q! m7 s - }2 g! Y/ O+ }0 B! Y
- //清楚中断标识# {1 L' ?; ~0 L3 e" G- w
- *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status
3 D8 G# R9 G6 _3 I$ @) ^ - tasklet_schedule(&CHIPINT0_tasklet);//调度底半部 / p1 P& ]9 P2 n1 P( c! \
- : ?# X. k6 i# t* E
, p9 N. T) x- F- return IRQ_HANDLED;; n7 o! O9 p( M/ O. N
! F% ?6 l! j% U) }: J8 Q& ~; H- }
! C$ `4 c+ s9 @; p; a
1 D# P; P2 E* A3 j7 t- //文件打开函数8 c4 _/ Z7 D9 V5 q/ c& D
- static int protocol_open(struct inode *inode, struct file *file)
) F1 Y, o8 {, E3 @+ a - {
, f9 f3 X2 M: _2 ?- m - int result = 0;
" _) {, `9 Q, b2 ^ - if(!atomic_dec_and_test(&dev_available))
5 N! }. W8 y! g# k1 s& g" n3 Y1 G4 h - {. n$ V2 f2 n* ^8 D- c
- atomic_inc(&dev_available);
9 V5 l& w* ], H; ~+ U! o - return -EBUSY;//设备已经被打开
: a1 X' o) f( c5 q' K% _; i; B: q - }2 c% c2 K. [, ]1 C
- printk (KERN_ALERT "\nprotrol driver open\n");
6 r5 a+ B8 C& R: V9 n - return 0;! [$ K) @- U* H4 ]! q
- }1 J! [% V- t. w* K- e8 J
- + l: ^8 Y. C& r6 t; l0 m
- //文件释放函数3 d" S8 q" j2 Y# H2 z% V
- static int protocol_release(struct inode *inode, struct file *filp)+ r; W5 [8 K( d. H) P. r5 Y- M
- {
]" t* A) b# h! ~ |, ^; { - atomic_inc(&dev_available);//释放设备,原子变量加1
! s. C, _+ A: i - printk (KERN_ALERT "device released\n");
5 ^5 ?( |+ d9 }0 B$ J7 `* M! N - return 0;
& O ~. w; }) K1 `- Q - }
9 t+ p9 I$ ^& } _2 p - & b; `& N: v# _/ y& u3 }
- //文件读函数6 \1 I3 ~: {& k- J' O# |
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)7 N# ^1 [& v/ `8 @$ v% R: T
- {* } ^7 N/ H# R- e; ?/ P
- int ret = 0;
- ?( Y/ ?8 y2 \+ ^ - //定义等待队列8 @* M0 g2 ^! i1 O: B
- DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列9 u! v2 A1 B. o% `) T/ v. e
- add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列5 _7 k$ B5 E- X4 J1 B" W* z
- if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
5 r) o* D8 I/ E& u3 h" Y - {
: K- w1 A& W2 f) h+ D. M) K - //printk(KERN_ALERT"\nbuffer no data\n");
9 n) x! c" t7 H - //如果是非阻塞方式读取,则直接跳出! ], ]0 P/ W6 B W6 e9 a. {
- if(filp->f_flags & O_NONBLOCK)! b6 c8 R ~! d. ]
- {' g, P3 z$ ~# F% g1 s
- ret = -EAGAIN;
3 J# z. P3 f' V, x) D - goto out;
4 k0 C6 v& c7 e$ d, X- D - }8 q7 a. ] ?# h8 O+ Z! E+ p* [
- //阻塞当前进程,放弃cpu资源
2 p/ ^/ d4 {7 c) F4 b - read_quest = 1;! h% K" K- G) ~ P8 @6 m
- __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠
4 K" x3 n G" W: G+ Q3 \6 p - schedule();//调度其他进程运行+ F G* b7 s3 S1 t0 H( E8 M
- if(signal_pending(current))" T, c# c/ P4 H/ f
- {* E* h4 b' t2 D3 r% Y- Y4 X7 C8 B' b
- //如果是因为信号被唤醒,则返回到系统调用之前的地方! V5 m; a6 d: K+ R9 ], z7 |7 D+ X
- ret = -ERESTARTSYS;- I; x5 A4 T* r t, l' J
- goto out;, i0 Z" j* n" A" {5 V7 o- ?
- }3 ~, Z" L7 z f3 V; P
- }9 E4 ~" n( c( @1 N
- //将数据拷贝到用户空间
6 f7 }8 C* u3 X - ret = k_linkQueue_getData(&queue, dst);. f4 B+ j2 d7 R' L0 U0 V2 d( {+ i
- if(ret == 0)$ X1 I' `/ ?9 i
- {# {: ^; c/ a( K; |1 a: z
- //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
# b& o% r( r2 O% |9 P# D2 Y - }
/ Z$ E X. m3 a0 J - out:
" h( r. F |2 a% ?9 n. }) ^ - remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列
" v8 t0 |# W x/ Z - set_current_state(TASK_RUNNING);//设置当前进程为运行状态" ?4 L, \. g. s3 g$ u" ]1 m5 e
- return ret;
+ w6 P7 R1 m8 y% y2 x - }+ n8 g" S! z8 I: l
0 K0 ^, O6 Z; Z! \3 z- $ T/ X0 l' f9 I- n6 R, l
- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)* l5 W8 ?1 W% B& z
- {- C! @- D/ H# y6 {" ~8 r
- return 0;
% X% U6 P4 u) n5 X: Z$ h - }8 Q: B+ W# g* M$ ]
- /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行- B6 d9 O# M8 g( } v( @
- open()、release()、ioctl()协同调用时被调用*/
1 u. r9 @2 U. ]8 `4 b. @ - static const struct file_operations protocol_fops =
" @% L9 t" k) b7 r& ? - {* P, t4 C ~6 z3 i c
- .owner = THIS_MODULE,5 L+ k. C0 y) i; |9 v# V5 B/ o
- .open = protocol_open,
5 E2 D9 q% y+ R) { - .release = protocol_release,8 [6 ^+ e9 V+ I
- .read = protocol_read,: o1 |$ i/ S3 O# V) f
- // .write = protocol_write,
% C0 k8 e! J4 M - .unlocked_ioctl=protocol_ioctl,% ~3 A3 ^( o; h5 L% T: U
- };$ S( @% W% [- q4 m) q. r+ B) ~
! Y) S& w( {! L [- Z' E) \4 a- /*设备驱动模块加载函数*/! T2 i# @8 v# n3 G0 A* m2 \
- int __init protocol_init(void)
+ {9 b- Y& H6 z - {; h: D& a( f" ?1 E7 _9 C$ Q' x& a6 ?6 g
- int ret = 0;
# _3 o) B7 T2 D( S7 O+ ?7 U - int result = 0;
5 w; ?# H: q8 H# f9 e. [- Q1 u - //申请注册设备号(动态)) Z% @! {2 b( W9 d3 B
- ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME);
" A8 G2 B8 l/ J0 L6 d" r, Q+ `- Z - if(ret < 0)0 g u3 N6 F$ F8 }9 n
- {" M7 F9 G0 y$ _& o
- printk(KERN_EMERG "alloc_chrdev_region failed\n");
' d8 r. ~) m# A - return 0;
8 D7 j+ N- R: J& N% b8 B* R) L - }
: e) Z8 z; w5 ~1 j7 B - //分配cdev) T# y) J V. q) f3 Z
- protocol_cdev = cdev_alloc();
3 `, s c; O+ C- o& t" Q/ v - if(protocol_cdev == NULL)) P" K% Y- |# @( Q. a
- {
4 ~1 T% v0 m( Q( ~ - printk(KERN_EMERG "Cannot alloc cdev\n");
6 @$ B2 _! H7 y+ k2 m - return 0;
' Q, G/ n2 k3 d4 e3 t - }6 j. E! Y7 r& T: z
- //初始化cdev
7 ]3 q+ g6 i0 j: R( `# H - cdev_init(protocol_cdev,&protocol_fops);
7 U# P. `% o& q7 z' T) H* ~4 f/ e5 L - protocol_cdev->owner=THIS_MODULE;1 e' o1 Z% \8 E4 m( f; [
- //注册cdev; }) h6 y5 \6 k& P( Q/ j. W
- cdev_add(protocol_cdev, protocol_dev_no, 1); - F' _/ |) X9 C% p* x
- //创建一个类( {) ~* H0 Z* i l
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);9 X) _$ u$ e4 L) Q8 Y" E/ t
- //创建设备节点
$ B4 E; L% t/ @( ^" y3 | - device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);4 S/ c3 U4 g2 L4 f4 P% }2 f. }# z
-
3 L" i6 M" |" B0 V. O - 0 Z" u) w2 [( W% \' N
- //申请链式循环队列作为缓冲区DSP数据帧的缓冲区
# }! y/ f( }$ e9 o$ y' _. q( m) @7 j" I - k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区
y# f2 I, B2 K0 r7 s0 V# T
- g1 n/ Y+ I7 j8 Y* O- //映射ARM的核间通讯寄存器# A! Y3 p7 w/ a# s' W) j6 V$ q
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);2 J s, x! D$ s
- R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);3 v7 A W6 d# p1 }& |7 t
- //将物理地址映射到内核空间
7 y6 N9 j$ v1 F n3 V- T - mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);
' |9 t* m( E3 v5 p+ ^( | - //共享内存初始化) O' m7 r: p- f( z
- SHM_ARM_Init((unsigned char *)mem_base);
: I4 [9 e& i" q3 ]" ]: u - /*申请中断*/7 H5 f: L; \' o! S
. N3 O8 q( @6 {8 U- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);
9 P* A: B- e4 ^ - if(result != 0)
: z9 T; \! X( T |& o - {
+ i# B$ x9 B: Q. {, y - if(result == -EINVAL)& o7 T! e. M Q( x
- {
: p& [& Y7 ?( g7 w7 }& [. s4 r1 l - printk(KERN_ALERT "irq request err:-EINVAL\n");
+ ^1 s. K4 x( \* ]- o6 m& h - }# s* n, K% t2 ]5 K' W% W
- else if(result == -EBUSY)2 H7 X$ T5 s) M
- {, h* U' H# T4 t0 g! t5 b B* M
- printk(KERN_ALERT "irq request err:--EBUSY\n");: a/ z+ ^- O& {8 _' X: Y) ^) X0 f
- }
8 N2 O' A* m3 t% q - else P6 O8 P, v2 ` y
- {
: o4 V3 Y! p9 e0 d4 O& B - printk(KERN_ALERT "irq request err: unknown\n");
. v& b& [8 p1 @3 | - }0 n& _; R& G& _, p5 M1 V) N
- return result;
, @& W+ m8 ~5 O1 z - }1 D9 B% N& B8 O* C( C
- return 0;
; \1 H0 Q1 t( C$ K* x. t - }' [% T# @% l& |5 ~! ?' E Z
- 6 E7 w7 A, D3 K. U
- /*设备驱动模块卸载函数*/
2 |2 j2 @. L6 p x) s9 U5 h - void __exit protocol_exit(void)' y; D7 O8 a% x2 a) E
- {. \* Q, B+ q* k# h
- /*释放中断*/% {0 f$ t& f, ?5 u
- free_irq(IRQ_DA8XX_CHIPINT0, NULL);
- Z+ c* k' g# B$ p" G- o* Y( c0 e/ p/ B - //释放帧缓冲的内存
8 @$ d+ x8 b/ R - k_linkQueue_release(&queue);2 n; Q- A' O) f: L5 ?$ x
- //释放寄存器映射
& {$ W% }4 _) A9 F - iounmap(R_CHIPSIG);# p& S: J6 {( W
- iounmap(R_CHIPSIG_CLR);
) Z2 ^2 g' j* S - cdev_del(protocol_cdev); //删除cdev
, |/ t" W5 [' Y" A u, Q" N4 J - unregister_chrdev_region(protocol_dev_no, 1); //注销设备号* K$ J7 i' ?( `+ K Y9 P
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
/ B2 b+ F! B+ {( L# J - class_destroy(protocol_class); //销毁设备类, e/ j$ x! d: A3 y a; |, Q3 e
- printk(KERN_ALERT "exit success\n");
, b5 G% G( \* E5 o) K8 F6 E* @0 f
8 y5 a+ Z2 U4 t% H2 P3 G# N- }, j" J$ j9 y! k, l! g2 a! |! [' ^: Z! g
- //驱动其他部分省略
复制代码
2 Y0 C6 ]! I" X$ _" Y9 s, u* }4 v7 J
|