本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑
7 p7 n- _9 U2 |
! G e; c, O/ ~! X项目要求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, I6 S& h. a3 M. c5 J - 0 V9 a5 f! _! [2 ^7 T- T
- //引入其他模块函数和变量: ^4 x7 y# C/ }+ f! c7 |
- extern Ping_Pong_Buffer res_buff;
! X! y& c. f, z$ A) w: e - 4 S- r( R1 f4 d N% @" I
- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列
" c# }- z A) d P" j - extern void k_linkQueue_release(linkQueue *queue);//释放链队列. r- W9 t& f3 Y4 C$ |% G7 j$ w) T H2 G' l
- extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据1 ^& e0 w6 v, [0 j- p4 F" B
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据3 u$ x4 G. D, \
- + v0 ^6 R* o, s' ]3 m5 e
- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化: O7 H& D, q. Q" g8 G7 T. h
8 \0 A' S1 [- r( M! Y- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置12 _' b ]! f/ X5 f0 j s
- //设置主从设备号0 g2 e% P- f+ T7 ?
- #define PROTOCOL_MAJOR 1. S) f( P# t6 W( p
- #define PROTOCOL_MINOR 0* ?% `6 y5 h$ E# B ]" x, S A( P% p# o
- # S0 D# v& x- K) B
" t [6 t1 }1 B+ B' j
Y2 D2 Z3 J a6 E- //定义设备驱动的名字或设备节点的名字( M9 V' N/ E. |9 j. O% g
- #define DEVICE_NAME "protocol_driver"7 j6 ~9 `% ~1 P- [. [/ @
- 7 z* N1 A, k& M7 B) _+ M
- ) h* a% T: G& R, J2 C% Y
- //定义全局的循环队列作为数据缓冲区
5 H4 s! a. o. {1 @: E: h3 P1 } - k_linkQueue queue;4 C" t/ m+ a; v
/ U+ u: f2 j6 V( r1 U- Z( \: _/ k: o+ X- //寄存器地址映射全局变量
$ x5 w, ^8 Y! g - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器
/ m# D) }! w) c' i4 D - unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器( R" d7 E' Q* E" [; V- I& k$ o
! r4 F1 S6 v7 t' |- //物理内存映射全局变量
9 v' r4 F/ f2 g7 m6 ~6 J - volatile void *mem_base = NULL;/ t, v$ s2 e& u2 g" m$ h, c1 y2 k
- volatile unsigned char *cur_buf_ptr = NULL;7 {' T' |- H. R' l" T% M
- volatile unsigned char *data_ready_ptr = NULL;
9 ^- O( k( Y& S# H, u - + u5 {9 r: v; |% Q4 |( C
- - ?* ]* v% n/ I5 [; g
- 4 }3 U* i% _$ K
- //定义读数据等待队列头,IO阻塞3 e; d6 f& @7 D% C
- DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);
/ q( U/ z+ Y1 ~. n+ f; i - " L/ W+ z+ S: S
- //定义原子变量
+ {5 ]7 h& R! U; f/ v( D - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备% ~/ ?) j# b. F
9 j! {$ n" l3 x$ v: p- * E- B$ a: y0 Q/ M$ K# |
- //定义设备类
6 P. t- ]3 s) [ y1 J' [# {7 N - static struct class *protocol_class;
" `$ Q+ J) Q) V: m( Q; {+ P6 L - struct cdev *protocol_cdev;4 T) B/ o' i \' s) J$ K
- dev_t protocol_dev_no;
- b4 f3 f: p1 X$ A, L3 L
/ _2 a( l& g6 i- /*定义tasklet和声明底半部函数并关联*/ _* Y' L6 f" \- f7 i. }9 ?
- void read_data_tasklet(unsigned long);9 P6 q/ ?, F" T6 x
# x2 z& k5 e0 O' O8 Y5 @- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
, y8 m) r( Q- n& K e/ E7 @ - //将CHIPINT0_tasklet与read_data绑定,传入参数0
3 Y1 |/ a$ x/ |/ [
# M! U6 }$ ^. i% i- /*中断处理底半部, 拷贝内存*/* l# ~4 W+ x6 C- B$ ~! P. E
- void read_data(unsigned long a). }9 r$ n2 S; n' X$ v4 A' @
- {* k# ^+ Z" b6 ~! g- f. o; T6 o7 B
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1
' {: x/ [2 f* W/ Y - {8 a/ ]3 {2 }& l6 S) D- W% t
- read_quest = 0;! z [, b# P# _9 y) ~
- wake_up_interruptible(&wait_queue_head);//唤醒读等待队列1 L0 l9 s, W8 x$ h+ i
- }7 H v; f3 c/ [9 g- w
- + s+ e2 w1 a' Y. J
- }
7 Z: H2 g# W1 H8 B5 E2 Q# j$ r - $ A9 L4 {6 n5 E) J6 w! c% [
- /*中断处理顶半部*/9 ^5 f: ]) h. P
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id): k5 M* [! o# m! [8 J0 F) q
- {% g5 @* M6 Q+ b. Q0 _3 m
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
2 {7 j2 Q; Z5 }& U1 U$ w( ? - volatile Buffer_Type *next_read;; |8 N; s: y7 E2 E. k( j" {
- //如果DSP数据已经ready
9 W% N1 w8 q2 R0 I - if(*(res_buff.cur_buffer->data_ready) == 1)
4 o& P7 N0 k, S* }8 z% F - {
' T$ ^( U. B6 O& ]7 x) ?# F - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer& T, \, m* f# }. Y+ f$ |9 _
- {
+ X! L+ T2 T2 P1 j! y) I - next_read = &res_buff.pong_buffer;//下一次中断读pong buffer* u0 l1 I% }' X
- //printk(KERN_ALERT"read ping\n");
, G! ~ Q: r! Q: I) |; N - }' h \- ~. L. K. v# ~
- else
; k" g! z/ Z; e/ ` - {; q" d `' F( V$ w; M- q* c) k
- next_read = &res_buff.ping_buffer;//下一次中断读ping buffer
0 u% J5 P& W( Z - //printk(KERN_ALERT"read pong\n");! y+ R1 m8 d+ ]
- }
3 z/ s0 Y: U- S& T( }9 x; a - *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer% j# b. {( u) k: t
- //将数据插入链队列
9 w! w7 \6 g8 D/ j [4 Q* e - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);9 X( g5 K8 K: t9 Y7 U9 y! d
- //标识位都重置- N/ Z- A0 l7 B4 y* U) H* ~
- *(res_buff.cur_buffer->data_ready) = 0;
8 y6 E4 k% K- r. K; g' g - *(res_buff.cur_buffer->data_size) = 0;" I- ^1 D' B) n3 Z7 z$ p$ i
- res_buff.cur_buffer = next_read;# X; p0 j! H7 \8 R$ C$ v% U
- }
6 D& s% z" r0 A( V7 S: u* @ - //清楚中断标识
7 Y8 p) p9 \+ [% b - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status9 r' g r) w" k! Z, o6 I7 z
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部 6 a: A0 j3 L( d0 Z8 B" e @& X
8 i; c L$ ]2 n) j' d* l- 8 F6 s8 N: M6 Y* u. C
- return IRQ_HANDLED;
8 a6 b: H) T$ h - 3 F! u: i) k( Q3 Q. w, |6 Y
- }- n# ~& |, Z. c; W
# b3 W& B5 ]: E& g- //文件打开函数8 X2 t; N0 y4 V' S9 d; d
- static int protocol_open(struct inode *inode, struct file *file)5 h- ]+ t# k. U0 \
- {
2 A" x ~$ ]3 C8 n - int result = 0;6 _ l( x4 p) U8 ` ~
- if(!atomic_dec_and_test(&dev_available))
& w% @; c6 o" }# ~' j: P# M8 } - {
* m' [" d c: ~/ E9 C7 M6 V - atomic_inc(&dev_available);
- D1 K% b f5 z2 f) V8 E7 H( i5 h - return -EBUSY;//设备已经被打开+ A! T$ }! D" Q* a
- }
- }# m, ?7 J! v - printk (KERN_ALERT "\nprotrol driver open\n");4 d/ j4 ?& f. ] L" K Q1 M( |$ E
- return 0;" |0 [4 w' ^0 T% c( |3 \
- } x5 @, g3 c' @) x: t4 p5 a
- : }0 V% y2 ?% P7 b' M1 k
- //文件释放函数9 |9 S% w, t4 [" U- M/ S! c
- static int protocol_release(struct inode *inode, struct file *filp)
, j' I) z9 r, C- p. _+ c - {
- p9 j) s' ?5 w- ?; H - atomic_inc(&dev_available);//释放设备,原子变量加1
2 ~6 D, F& C) @# M. K; i - printk (KERN_ALERT "device released\n");
" ^% L# Z, X' x1 W! n; | X7 y - return 0;
& [+ u, p; B$ e) m9 _& c, O - }4 F7 v5 v: T6 s0 `& g( H
- ) S4 b; o. ?6 l% D ]
- //文件读函数' |6 b; c/ a5 l2 z* e
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)
2 B5 P2 h; k4 h/ v2 F& w Y - {& ~) c* t. r! M' ]1 u* S% @* Q
- int ret = 0;, ^$ J: Y- F8 Z
- //定义等待队列
5 J J! d; ]' c$ w) R+ q5 P, @ - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列
( G j" s# U* g - add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
" j. @5 B! m3 z: _) B - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
" Y3 o! ^/ ]2 B& H - {) P8 Y5 ?% o s) `
- //printk(KERN_ALERT"\nbuffer no data\n");
* T4 Q& n1 Y, N( j, ^1 e - //如果是非阻塞方式读取,则直接跳出
( U) W( x/ _) D6 h - if(filp->f_flags & O_NONBLOCK); V. y6 b5 R1 n/ G( N( Y# ~8 _0 ]
- {* o2 g1 E2 P0 K! g4 u; r
- ret = -EAGAIN;, s7 [" |. \5 Y" a$ g7 F
- goto out;
! x' D6 ~6 T: x$ Y" ?/ i4 i8 J! \+ J - }
1 {3 |9 W( x8 P) m( G - //阻塞当前进程,放弃cpu资源4 g& F# S4 l% c4 p/ A4 t1 S1 X
- read_quest = 1;! X; b) P: R5 ?1 X7 g! v) h" v
- __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠
6 n+ P+ V) ^3 z7 t" v2 b/ Q/ Y" I% o - schedule();//调度其他进程运行4 ^0 N' [% E; }( T) A9 W" j
- if(signal_pending(current))
# Q8 ]! d! T4 ^* W o2 A4 Y - {
6 O4 ?$ j8 N. c - //如果是因为信号被唤醒,则返回到系统调用之前的地方9 g$ z' Z% C2 J2 M% b; G8 L$ {1 p
- ret = -ERESTARTSYS;$ M t- ^- }7 b3 N' \
- goto out;
$ V" X# @/ r/ G% ?( Z& c - }
% N/ U+ G, b/ _5 n* r' ` - }
: r. v8 t+ b8 o7 @, Z b1 o' A - //将数据拷贝到用户空间$ P/ {# y; Z: p- B" G! B! ]
- ret = k_linkQueue_getData(&queue, dst);
0 ?# J ^$ _* V9 h - if(ret == 0)
$ l( f, j1 N: n/ _4 a0 Y7 g$ j - {
' O/ P1 c Z9 Y, o5 |) A Y4 h8 Z - //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
: u& B1 {+ K' Y/ Y/ Y7 Q D/ h% J - }
, p- G' ]8 M! S3 n - out:+ U2 G8 J- B" [" U) q1 F
- remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列
) A/ j9 F) Q- {: [ U6 E+ R/ Y - set_current_state(TASK_RUNNING);//设置当前进程为运行状态/ k( x, X+ w0 t' W' e+ K6 i
- return ret;
6 S% t- A Q* e, T$ j* y! X; v$ ], ~ - }
# e5 ~+ C. j/ H. C" O2 g. W9 n6 q! g - 7 r$ M- c- ]+ L
8 X3 q4 V! L6 O- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)
* Q$ q/ A/ k( a% z! d+ q4 M/ d( ^ - {$ Y) n6 i4 r1 H8 R
- return 0;: U9 p/ m( v5 M4 [. Y
- }
; Q7 w! Q* Z5 i9 w- g' R' T - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行3 A' Z$ `4 O1 `; D* q) U$ U
- open()、release()、ioctl()协同调用时被调用*/( E" }9 E8 w8 w0 E; k( V; J
- static const struct file_operations protocol_fops =' A% U' f9 `. n1 ~$ E3 M/ \
- {; _# L6 A: X% Q6 [
- .owner = THIS_MODULE,
0 W Y9 b1 e# p* y2 F: r F - .open = protocol_open,
& f. V" q8 c2 x9 W# K/ D) J - .release = protocol_release,
7 y$ z# T# m& _ - .read = protocol_read,' ?" P6 \1 ]! ~" b$ @, a' X$ F1 r
- // .write = protocol_write,, O5 [1 W5 N3 _3 d- N; M" y5 z
- .unlocked_ioctl=protocol_ioctl,- ~, Z2 p# c3 \$ Z
- };
3 O$ L* L5 L3 M9 I( f7 Z1 [. W
% o% v3 A% A6 L& n- /*设备驱动模块加载函数*/) h% z* l2 u8 F; c5 R& R, |
- int __init protocol_init(void)
/ s/ E3 }: ~8 r& s/ E$ q* J/ @. e - { A, K Z) h$ O* Y Y- Q9 ] d |
- int ret = 0;2 p$ a& ~7 t5 q: Y2 w
- int result = 0;: R. g0 r) k2 g6 B- u
- //申请注册设备号(动态)) K+ U6 u' t7 a3 F0 R; s1 u; G
- ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME);
& z' Z' \% t( R; ` n - if(ret < 0)
" _, v5 Q u+ S2 ] - {$ E# e/ a" ^0 i. {. ~4 R' \
- printk(KERN_EMERG "alloc_chrdev_region failed\n");0 ]$ U5 n& g3 R
- return 0;
' r- w2 ~( O' x% x - }
& L2 m: P; s- p. @ - //分配cdev. F5 ?- k; T7 g, @0 Y4 u. r
- protocol_cdev = cdev_alloc();, M3 y( x& N6 ^: N2 e4 a
- if(protocol_cdev == NULL)
6 G7 o: u5 K( Y, {! `; N4 a# z2 W - {
0 H( v, n( Z3 m* N, F+ ?: e5 Y% A - printk(KERN_EMERG "Cannot alloc cdev\n");
6 G% x0 `1 h0 M. s: E; x - return 0;: i7 M1 f' }; H" n) b
- }6 e: u/ u; I" C/ g6 g$ v9 Y! U! p7 H
- //初始化cdev3 f+ x0 L# I2 g) z1 S) |& R5 v
- cdev_init(protocol_cdev,&protocol_fops);
8 S- q- j Z4 A1 a - protocol_cdev->owner=THIS_MODULE;
1 t/ i$ }7 j/ j1 f# I, u: \$ A - //注册cdev4 P; f D! ~5 k4 W4 q
- cdev_add(protocol_cdev, protocol_dev_no, 1);
, K; H; n* Y8 b9 C - //创建一个类
8 V, p: h% W, j7 y& U+ i) ?) r - protocol_class = class_create(THIS_MODULE, DEVICE_NAME);4 A, e$ j9 {5 Q* @3 Y& H
- //创建设备节点
( ?' \ {. d. `1 C1 k U. V - device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);
4 F- C* P/ Y& L' E3 y4 ?* E -
) j- f/ R+ _1 K# Y4 u - $ ~4 ^! o9 N# w4 c$ z
- //申请链式循环队列作为缓冲区DSP数据帧的缓冲区
5 y* U- y+ k" z+ Y& [' K0 f2 L - k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区; P7 |3 X3 V5 c f6 [
- & x q$ {7 ~% D! U
- //映射ARM的核间通讯寄存器0 M* [$ L) ^: d! u5 A
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);0 Z1 i$ P3 a1 P _1 b
- R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);
5 ?( @* K3 q: J" v& L, t - //将物理地址映射到内核空间
7 t# {2 C& R$ J6 C6 H6 Z - mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE); C& ?# v5 I1 [
- //共享内存初始化
6 S+ Q; N( U4 @ - SHM_ARM_Init((unsigned char *)mem_base); I) _" b, Q1 q
- /*申请中断*/6 B8 s! a3 q1 j B
- . A" p( k0 n6 h: \4 v! t2 K
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);- z7 s& a0 c Y: @, U ?
- if(result != 0)
: U, _5 f7 k$ V l/ n! D9 H7 r3 e - {
! S2 J ]' T3 S8 N) a" p - if(result == -EINVAL)
$ J7 Z- {% [9 Q) }0 r - {- C/ C z( u9 b+ b
- printk(KERN_ALERT "irq request err:-EINVAL\n");
- J9 O) R+ a1 w4 `/ z; y4 Q: A2 ] - }( c) b% w# w5 a1 N2 i! f$ Z
- else if(result == -EBUSY)0 n% l! `& ]2 z& {+ _
- {7 r% F ~% L) J5 S8 S8 p; f
- printk(KERN_ALERT "irq request err:--EBUSY\n");
: i$ |) O& x9 s6 `0 \: h - }
2 Y- ^( q, y( F& ]3 {+ Y" X$ j - else
7 U! r8 i2 J$ [ - {
9 f$ p8 t; I4 Q( _1 q& t - printk(KERN_ALERT "irq request err: unknown\n");) a! W+ j7 d8 s' ]# N! l
- }. T+ Z4 Q Y1 o' E& U9 g6 C) q
- return result;
8 ]8 q% Y z% L% e6 A - }
& {7 p. \6 |7 [; o: c9 R - return 0;
j( G& z. d0 X3 T" G - }
( W; U- v! J& l/ b - 6 a6 ^, I9 K7 f" i
- /*设备驱动模块卸载函数*/
/ x' F# U3 M! D; M- J$ Q% `4 k& K5 n - void __exit protocol_exit(void)
% n, w: W6 o9 B& s4 Q% z3 I - {
2 x) n% F# g& Y V$ m- p* y - /*释放中断*/
4 _" s; |; M% J& \& T: [, Y5 D0 X - free_irq(IRQ_DA8XX_CHIPINT0, NULL);
" A0 `) C2 p+ F8 x! ~: i% c; k - //释放帧缓冲的内存* M: K. h5 H( D
- k_linkQueue_release(&queue);
9 y/ d0 D& m4 G' S - //释放寄存器映射
& ~6 @; u6 G3 h/ C - iounmap(R_CHIPSIG);' i% X* x Y. M! E! H( K# J% B
- iounmap(R_CHIPSIG_CLR);. ]; Y+ _ Q U9 e0 J; a6 W
- cdev_del(protocol_cdev); //删除cdev- B0 L5 C3 R2 y
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号& f3 m; l9 j3 d
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点6 P+ B5 s1 X' y h1 n% P5 J
- class_destroy(protocol_class); //销毁设备类' d" U1 U0 k6 l& W' f
- printk(KERN_ALERT "exit success\n");
% o* D7 I8 t) N# Y4 o- ~
' o# ^, q& b$ c; U- }
; B* R0 h2 K! {2 p* ]# n& _( q' ~) Y& @ - //驱动其他部分省略
复制代码
& b* l/ B: {. Z; M% f5 y
+ T0 i4 I7 ?9 h) N3 E |