本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑 ) B: a8 B4 F% @8 {. G% {- k
! Z# Z0 N) ]5 Y/ k
项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略
O b6 p! z0 x9 t: W* J* w7 o - ' D0 H- I( z5 v
- //引入其他模块函数和变量( _8 i0 F t6 V/ M! y& d
- extern Ping_Pong_Buffer res_buff;
7 U; ? F1 V) i% z& w7 j) D3 c
+ d/ W' X4 q7 U9 i- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列1 x. H2 B" ~5 j/ g8 P; |9 P
- extern void k_linkQueue_release(linkQueue *queue);//释放链队列( e r: H. c7 z8 i# s5 C9 f
- extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据
; ?" d0 x# Z3 A( O5 D - extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据/ i6 i$ j" @1 Z8 i0 y. Q- G2 }
- - T* F; e; U- e, y& i
- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化: M; n6 L* H3 M. b9 \1 P; p
- ! g5 \0 U) `5 ~7 h% H5 F% o3 Q4 n
- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1
* @ b) y/ B' g7 P0 l6 C) s( ] - //设置主从设备号9 w5 w# P2 R- _2 d
- #define PROTOCOL_MAJOR 1) v# S9 Q( @4 Y i; A3 |
- #define PROTOCOL_MINOR 0- z% \) g0 g0 _8 \4 [! O
- 4 S9 J" E8 ]3 u1 v8 M$ a
- " l. Y( }2 r+ Q6 W
9 S7 m6 P* v' [. C6 Q" l% K8 a- //定义设备驱动的名字或设备节点的名字& s, k; h7 g+ K- I7 s/ ?, d) ^
- #define DEVICE_NAME "protocol_driver"2 g' T3 c3 M( C1 @! e9 h
9 U9 V9 E, t) z* z
& i* l/ x- }$ {/ w/ h- //定义全局的循环队列作为数据缓冲区
, O* }8 J- W( c* z8 t3 T - k_linkQueue queue;
* m" U$ k3 r2 \! ^- J8 \- Z5 @ - . d/ K0 i4 D; u
- //寄存器地址映射全局变量
4 b ^, ^8 Q, n' x. i - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器
: e5 r6 ~% M! V4 \* R - unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器8 N# g) ^, q4 y5 r3 ?
o7 u# B" r3 O, [9 U- //物理内存映射全局变量- E" J# H0 v/ b7 _. E
- volatile void *mem_base = NULL;! M9 O4 H* H2 S P. X, g% y6 z
- volatile unsigned char *cur_buf_ptr = NULL;
% S3 v- h# D" U" C d- U' A: [ - volatile unsigned char *data_ready_ptr = NULL;
7 R' z7 d6 u; }& ]( {; P4 g' A - 8 }+ U8 \9 A. B! Z1 d
( u( t$ P. @- x/ Y- g5 E8 ] a7 i/ L$ p2 j: Q# j% P- n
- //定义读数据等待队列头,IO阻塞4 z: k8 z6 m/ |* h9 E9 Z
- DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);
" x( b5 l1 ] x9 E! _ - / G6 M$ y( C* g/ _8 @
- //定义原子变量& d( J1 A. g% V( d
- static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备' t# {# L2 T8 y& y; U
- 4 P: i: b: N: G3 U' M+ H5 Q/ k& u
- 2 F$ O: I+ w( P( q: ]
- //定义设备类+ a. N6 N1 I @% F8 z
- static struct class *protocol_class;
4 E# ~3 [$ n4 b! G. Z* ] - struct cdev *protocol_cdev;$ |* ^2 k+ D8 Q3 h
- dev_t protocol_dev_no;
2 V3 l' e6 v7 f8 ~* v. U# `) }" ? - # a7 k. S5 K# ` m" K7 G6 |
- /*定义tasklet和声明底半部函数并关联*/
& ^6 v5 P( G1 B0 t B - void read_data_tasklet(unsigned long);) q% f, @4 p% P( r+ u
- 3 H N" i6 G, S3 Q9 i. k4 t. s2 Q
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
3 y Q7 ~; z% {% d& @7 M - //将CHIPINT0_tasklet与read_data绑定,传入参数04 i b) M/ k& }2 K G) j
- [1 W O) r8 s8 }" }! D- /*中断处理底半部, 拷贝内存*/: S- `5 ?& v; ^ d9 g( W9 y
- void read_data(unsigned long a)$ M* o$ g, \4 W/ `3 T: p
- {. X- `, P; h$ M
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1
! b e1 E. R6 z" `/ x7 U - {
! r; N, R% T+ V. r5 w6 A/ h - read_quest = 0;+ E1 M0 S7 i- }' B( }% {9 r
- wake_up_interruptible(&wait_queue_head);//唤醒读等待队列- `( t# p: A8 Q3 U5 p5 G5 N E
- }, ~5 }9 h; y: G0 o7 v3 Q; H- P
- 0 y1 X$ h E6 T; W( b
- }
9 J' W8 |& W! V0 B# W% s - 1 b0 X0 H) J9 }8 p" t
- /*中断处理顶半部*/
) x8 \( o1 H' r- h7 y2 H$ t$ N - irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)
3 B6 U, Q8 t8 I7 ^3 n - {
2 r# g- L1 }, D) B' b+ f [" H! ]: L - //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
6 I$ g# h8 D& s9 E3 t - volatile Buffer_Type *next_read;; M, \( I- c8 s0 S/ x
- //如果DSP数据已经ready9 X' ^5 K: q5 J& }) \
- if(*(res_buff.cur_buffer->data_ready) == 1)% }& ^$ P0 h& w" v7 a% n/ p
- {4 [( ?, q) r% z( s: {# e8 R
- if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer
5 ] M/ C+ `1 k" ~* @ - {
8 f1 J. P0 T# | - next_read = &res_buff.pong_buffer;//下一次中断读pong buffer
+ c% q1 r3 P$ L1 j7 b7 Z! R6 M1 [# J - //printk(KERN_ALERT"read ping\n");7 F; L" |3 t! D: k1 D
- }6 E6 h7 R5 a: h; u" \" U
- else( U# e. T$ A' B3 k$ _! ^6 R
- {
/ K/ }7 N8 t" ^4 Z8 s3 i - next_read = &res_buff.ping_buffer;//下一次中断读ping buffer
" e$ J) M- Q& B - //printk(KERN_ALERT"read pong\n");
8 t8 v" A$ Y. r2 ~5 z) D - }; i. l: h8 j9 b+ h& R
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer% `8 F! C1 t+ V% z7 q2 q# ~5 c% H
- //将数据插入链队列
0 z6 U! I- l1 C - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);$ h- y& G8 ^! B; j
- //标识位都重置
: ]; E5 @' X. m% `, @ - *(res_buff.cur_buffer->data_ready) = 0;
8 D- B( d g# [3 ~! @ - *(res_buff.cur_buffer->data_size) = 0;
: ?! {6 Q, ~% H$ o" O) @6 f - res_buff.cur_buffer = next_read;& c b$ K: a0 u9 T2 D. ?
- }
4 y$ U& N7 V) N5 n2 q# b ^ - //清楚中断标识
; q; d7 J& M* X - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status
) D: V9 n& F7 F/ s- E6 o* N - tasklet_schedule(&CHIPINT0_tasklet);//调度底半部
5 ]) {+ i1 z$ i( B
! u9 B/ }. A# T# U4 S
" L) M, l1 _: g% c- g) E- return IRQ_HANDLED;1 {# J d: k! o" K7 z
: Q7 z+ ]. V0 N( R. \6 ?$ k# V" o- }
2 c* f, R V T1 x# Z - 1 J. Q3 w9 b; ], x! B
- //文件打开函数
8 T4 \9 z6 m# d6 H, S( D - static int protocol_open(struct inode *inode, struct file *file)
; f R2 N3 s# m+ K$ ]" Y2 V- v; ] - {
+ h8 W9 O( ?3 Z1 q# Z! A - int result = 0;* K, ^4 T0 T) ]2 d2 Y' C8 S
- if(!atomic_dec_and_test(&dev_available))
1 b' k0 r4 e5 L* ? - {/ G+ T7 ^) a2 x ?6 J
- atomic_inc(&dev_available);
' d4 G& v* j6 o) V: z- E ] - return -EBUSY;//设备已经被打开! C' I0 c" h n; L( Z" k! K& x
- }
9 x& Q% n+ A* r - printk (KERN_ALERT "\nprotrol driver open\n");
3 r$ j1 z h; k( C - return 0;
9 s! l0 Z- l l$ J% I/ Z9 r - }
" F3 ` T$ t5 ^; g - . l# Z2 C7 C. j' j
- //文件释放函数$ O& `! h3 ? ^2 j$ x7 D" U4 J
- static int protocol_release(struct inode *inode, struct file *filp)
. s( T. |' z5 f& q( w - {# w/ o" e5 O( H
- atomic_inc(&dev_available);//释放设备,原子变量加16 |( u& Y' L8 }; ?
- printk (KERN_ALERT "device released\n");
0 w) r* b* x& G' K) B - return 0;
! _" m2 V2 I& L& c- [ - }( }- j1 {% Y2 @; c t: L
) w! U+ `! [" X; I B- //文件读函数
% v) D; [; X! P9 Q( H - static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)+ Y6 j( k/ J2 m, Z& ]
- {, l+ z; ` d) ~1 a. w0 s
- int ret = 0;
# q) ] ` p" f" v/ _% o - //定义等待队列' ~/ E" P+ c: p: D- s
- DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列
" P: x! K6 U8 _; f; m - add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列# }6 z1 Y8 Z$ q- L K& P4 N- Q" [
- if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
6 U4 U& f2 z9 O, d) M - {
7 |! U; O' I# Q3 X! ?+ ?) p- L+ _5 B - //printk(KERN_ALERT"\nbuffer no data\n");
' L3 b& g, A: g. K A9 ], q - //如果是非阻塞方式读取,则直接跳出( G" u- r4 E g( J3 g6 c
- if(filp->f_flags & O_NONBLOCK)
U; y8 |9 m; R- P( F6 ]+ R8 u* y8 g$ j - {
7 m; o, ^8 L2 _9 q( k - ret = -EAGAIN;
& u* J6 I2 K$ E3 }& O - goto out;
2 ?% v6 P3 l$ h7 w$ Q - }6 o/ }6 f; G/ I0 N5 y0 j! I' @2 n
- //阻塞当前进程,放弃cpu资源
4 m+ _& A- m4 x! L( S, y) ^4 F - read_quest = 1;7 [1 R Y7 i6 ], }8 ?) m7 H
- __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠6 n6 f: G2 c, }4 \
- schedule();//调度其他进程运行/ z& h7 d, H. v1 a0 @( {9 w
- if(signal_pending(current))1 W6 `; y& M8 O
- {
- B7 I9 N$ {" {' L2 N- g) F& ?5 ~ - //如果是因为信号被唤醒,则返回到系统调用之前的地方; f0 [% m$ N1 G3 q U+ F, Z/ O
- ret = -ERESTARTSYS;
2 p' v7 o& b: J2 {3 K8 ? - goto out;8 V1 u7 Q Q! d6 G5 x
- }
+ l) X* f7 d* { K2 r - }
4 W1 t) r/ \ h6 ^6 g# J - //将数据拷贝到用户空间
& J5 o( [0 B. M$ h - ret = k_linkQueue_getData(&queue, dst);
$ f; I( p3 S; q - if(ret == 0): E6 c+ `! B0 o \& J9 W* H& f m3 V3 R
- {' Y7 r7 S1 W. ~, `" ?
- //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);7 p: s7 |5 z) j! Q y! z# o( v) _
- }! Q. t; L, b7 g# G0 C$ Y
- out:
) ]+ _ ^6 h- ^, U* m/ } - remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列
4 @; h3 J0 T3 F5 }* \7 Z1 | - set_current_state(TASK_RUNNING);//设置当前进程为运行状态1 d4 ^" H6 R7 f
- return ret;
: U* k6 c4 t' T8 I' G( l0 [ - }) R d! ]; C9 F2 G6 K* h
- ( M! O4 x$ w, Y$ w! g2 |0 A% V# x8 _
/ g0 e* _$ f2 ~; U; q& |$ v1 ?* _- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)
) n: h, R, I; k - {' A, h/ l+ u' {; S4 R+ c
- return 0;
6 _5 m6 R0 J/ }* J - }
$ e- y1 i7 `: E- k2 P( N7 {& \ - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行
9 f; h+ A/ i, G - open()、release()、ioctl()协同调用时被调用*/
& Z' T- x5 l* ]% n2 z - static const struct file_operations protocol_fops =
2 H' E8 m6 Q1 H - {4 L- z( t" `5 @$ k: k
- .owner = THIS_MODULE,
/ l% X6 m' @ y8 W8 d - .open = protocol_open,5 f: _) G4 L. ]5 |% v3 Z: c
- .release = protocol_release,; R/ x; p& \7 @! W. ~
- .read = protocol_read,
5 `. R1 T# J3 V, d S3 I9 M$ t, f: D - // .write = protocol_write,
4 ~, A5 C) Q9 U: u" G, {( Z9 R' r - .unlocked_ioctl=protocol_ioctl,8 k$ F. x% R- U- ]( W6 c# Y1 q: | X+ k
- };
5 s& @3 N& |; Q! P# u
* d* {1 j; W2 b8 J* D) [- W7 R- /*设备驱动模块加载函数*/
) V, G0 `$ k. S- b - int __init protocol_init(void)
2 ^" |& q) [( ~* ~4 s& ? - {
) Z/ D6 ]; ^/ H - int ret = 0;. A9 W- s& n' k7 a- w# Z* k
- int result = 0;
! p7 w4 e5 r, a# s6 @3 A1 w5 i - //申请注册设备号(动态)0 C V5 D' |; @' k7 L0 \5 A
- ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME);
" N, \$ h0 i3 g! |& B4 S9 m - if(ret < 0); t( k; f8 i: Q
- {
- E8 P% ^- k4 Q4 v2 U% d - printk(KERN_EMERG "alloc_chrdev_region failed\n");8 G. T7 M& h7 t& J1 h
- return 0;! Y7 T6 C$ {+ W/ Z
- }) i5 s# s6 q. V+ q
- //分配cdev
, L! b; i2 h& U - protocol_cdev = cdev_alloc();' v$ f: b5 X% ~7 {2 B. Y% n0 F
- if(protocol_cdev == NULL)% V+ l' t' b# ?, H7 T
- {
- S/ r. H0 N0 @$ M9 |8 g - printk(KERN_EMERG "Cannot alloc cdev\n");' o; E- [% B( R9 G+ T' @6 J9 C. ^5 R
- return 0;/ m; h( ?& Q/ a# W0 `4 B4 L
- }
( T, U9 D' s( K6 r3 Y6 i M - //初始化cdev# G# J$ W6 ~0 J5 k
- cdev_init(protocol_cdev,&protocol_fops);
' B; ^' ]) F ]' [+ L/ W: H! _& ] - protocol_cdev->owner=THIS_MODULE;
6 o* M- J% H6 n, w5 Z& { - //注册cdev/ b+ o+ f6 x2 j- O0 w
- cdev_add(protocol_cdev, protocol_dev_no, 1);
5 z0 a- M" q& B4 Q/ m1 a4 I - //创建一个类
3 p1 H7 l, w9 D o0 b; v# j - protocol_class = class_create(THIS_MODULE, DEVICE_NAME);/ f+ b- S! J' f3 J3 h
- //创建设备节点0 {" h# C3 ?8 Q; a% k. d4 S' u" u
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);
" V" q' S5 |; L" V: B$ M -
& \! T8 k, z3 q! X8 D* ~ - ; x: ^& {( W' ?1 r h3 b1 s
- //申请链式循环队列作为缓冲区DSP数据帧的缓冲区" A2 G5 J& G) e1 z+ v; H
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区/ j0 @3 z* R+ S/ n- w' a+ i
. N ?# i* o; U( n2 G) R8 q- //映射ARM的核间通讯寄存器2 A/ E& z1 N$ N, t. G: v% e p# F% Y
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
0 b. D- `' [' {& m6 ?- f8 t - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);
. Y/ U7 W3 C4 J) B+ o" \ - //将物理地址映射到内核空间
4 i% s6 q% X( m% U, ~% J - mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);" i* A8 D w4 Y( S0 |6 r( F
- //共享内存初始化
3 R* d; E& E9 G+ i1 e. @$ u, U - SHM_ARM_Init((unsigned char *)mem_base);$ i0 o9 ~ u& F' c
- /*申请中断*/
% S, F) h5 Z! q$ B0 Z7 i$ u
R$ Y& `* k3 X8 Z' g- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);! T6 A! ]. O' x& V
- if(result != 0)2 x8 ^# W% f* U. X& A O
- {0 `/ M' r2 b0 \0 ~& V" {2 O
- if(result == -EINVAL)
7 c ~2 u! E1 W3 v& e - {
+ J. i8 d5 u/ z' \ - printk(KERN_ALERT "irq request err:-EINVAL\n");
) }) @7 `5 T9 j/ o - }
5 W( P( b# ^7 q - else if(result == -EBUSY)" G4 U2 i, e) x$ D. h5 I
- {
% W* n5 R" j& W* }" W# a( i# i - printk(KERN_ALERT "irq request err:--EBUSY\n");
7 }2 `7 g U" `, } - }
; |2 U! x. M* M' k; n4 G, ]( F - else
; b0 n! O- |* J7 d - {
- b# U' v) V0 l$ E9 w - printk(KERN_ALERT "irq request err: unknown\n");
( X0 J& A8 n0 B - }
6 P9 @; T8 c& t& q" {# g Q& I4 U. k - return result;* A& m6 t) ^4 ?1 x& j0 k. @
- }3 a+ w2 x+ O. E- b/ [
- return 0;! n* F. d7 g% Q/ Q9 \9 A
- }
8 y* I; f, c& M, P7 ^/ i" Z
7 S0 f* a0 b3 u: P1 v- /*设备驱动模块卸载函数*/: N# C0 w$ z3 g {
- void __exit protocol_exit(void)
% E. S+ o& u. F - {
4 F6 x$ E9 G& g7 i - /*释放中断*/
& p3 w$ J1 t' i6 d# _) ?& u - free_irq(IRQ_DA8XX_CHIPINT0, NULL);) O; ]: H- w" ?: n
- //释放帧缓冲的内存& W& K+ @! o+ _) p0 w6 M
- k_linkQueue_release(&queue);
# P' M! c6 I" I/ X - //释放寄存器映射
" q5 x* j- L$ e7 A( N3 N: e - iounmap(R_CHIPSIG);
" g ~% n0 X F/ l1 E - iounmap(R_CHIPSIG_CLR);/ n- F+ o8 B5 [$ K$ X5 A8 J8 ], }1 l% I
- cdev_del(protocol_cdev); //删除cdev, ]2 A3 l$ O4 U5 y0 Y8 W! ^
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号
! B( Q/ U+ \+ {. v# e7 E$ z - device_destroy(protocol_class, protocol_dev_no); //销毁设备节点' S) l: ^+ P9 z4 l
- class_destroy(protocol_class); //销毁设备类
( ` d8 e' [' L4 Y; M - printk(KERN_ALERT "exit success\n");
" a1 S5 J# m; y. q4 q8 O( n
- \6 ~% g( G8 v! y- }
; a( A- K* J5 g* A( e - //驱动其他部分省略
复制代码
2 D0 w3 m: T# I+ u; b A9 O
6 r# X0 \9 a, r0 }: s |