本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑 . l. y0 I3 A1 T% ~
8 y& w) r. x9 T# 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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略
" h. p' ]) o( m1 Z' h
5 U2 u* w% L: a( x- u( m! P- //引入其他模块函数和变量- G/ a z4 x5 f, m
- extern Ping_Pong_Buffer res_buff;
) E, ?7 D# n+ l, ^ S: O - , \& p1 d7 O% _% u7 h
- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列) V& G# C/ V4 l3 k$ Q4 F% C D, }8 w
- extern void k_linkQueue_release(linkQueue *queue);//释放链队列
8 l) G9 @. P O+ A" Z" Q - extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据: U4 w8 Q% w; Y5 j6 }
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据
" e( V/ |4 J" p9 E$ a - # H. f/ h' [1 d7 u A( ?6 R
- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化
( R- l$ S0 J# j% v: f - ' i/ s: e' u' V4 e! y$ O6 Y4 H* A5 d
- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置18 X* y0 }; u2 R
- //设置主从设备号. h2 ?* C- d& C1 o9 S7 q
- #define PROTOCOL_MAJOR 1, q; v! x5 a" g+ ]$ Z$ X9 b
- #define PROTOCOL_MINOR 0
) n& o9 n4 `. b& `. d! C - : a' _+ x' H1 W3 N q" o
- M" L% W( l1 [- K# [' a$ U9 S, Q( b/ z- & k" c. w& B+ O _, Y
- //定义设备驱动的名字或设备节点的名字, W' ?: ?2 f/ r" \9 {
- #define DEVICE_NAME "protocol_driver"
: I. _8 n) ?% \) r9 R" Y+ o - ) J8 L! |. [; o, w! _6 ~
- ! M3 j3 K# N! W% M: g
- //定义全局的循环队列作为数据缓冲区+ X; O+ O1 }! [- R
- k_linkQueue queue;
4 Q+ W8 P# {6 v/ f+ `6 A Q; a- `8 @
9 m$ L, O! J3 l" D% p+ k- //寄存器地址映射全局变量
5 O1 _" a) N* f! g - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器1 I8 f F0 D' z2 c! @3 z
- unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器/ [ T# ~. \( {/ ?- h
- ( M$ L6 _8 J9 V; K
- //物理内存映射全局变量8 j- \" i; E2 |# J( g. y( T$ `
- volatile void *mem_base = NULL;
$ I9 C! M3 W9 Y4 b: H& F, K# J - volatile unsigned char *cur_buf_ptr = NULL;$ @3 B4 _4 ^8 L7 Z3 |
- volatile unsigned char *data_ready_ptr = NULL;! \( l+ j! L7 g, i* U
8 |6 O6 a( ?: H; r3 h3 a, j
4 m8 N4 d9 K5 a5 L
0 x1 y! P" K, [- //定义读数据等待队列头,IO阻塞
) q, {2 a1 K% F5 }- P - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);" w( [9 o' r$ H; T0 G- i W- _6 C
7 x, W! A- t4 s- //定义原子变量
) z7 g$ o y) U - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备, V: C- O+ V, T- X
- : a/ g6 F9 r7 Z. g. N
- . \% }, [; q% l
- //定义设备类, A6 E# Y0 o+ Q8 D n3 @
- static struct class *protocol_class;
; D3 U$ {: }' R' k+ [( n, f - struct cdev *protocol_cdev;9 a* M4 ~% K% y8 K1 m
- dev_t protocol_dev_no;
6 n0 S- H- G: A
& |9 s, y9 @1 W- /*定义tasklet和声明底半部函数并关联*/
! ^ `7 [% Z2 k- a; i) e& ?5 N - void read_data_tasklet(unsigned long);
) `) Y0 `$ O; {4 \
( u8 b' b! K8 X0 p- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);1 x. K* l$ S3 @
- //将CHIPINT0_tasklet与read_data绑定,传入参数0
5 ~1 ?& p- s1 }9 a - 4 a4 S5 @! g# S" `
- /*中断处理底半部, 拷贝内存*/
8 p$ A9 k1 P4 d5 X3 K - void read_data(unsigned long a)) M7 g5 y. i5 M8 i+ p2 Q: b
- { V: J6 j5 C& U
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1
`& O$ _# }/ j2 Q3 f - {
p& E/ S9 G- d- E$ C4 B8 J+ k - read_quest = 0; U. p6 j& B! K0 c
- wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
7 T) S/ X- t6 M6 ] - }- X$ k: O; g O
- $ i! F* F4 }9 O, J. ?* h
- }( b8 K7 s( o1 i) M- b2 \
- 0 W6 I5 \* M, L" M3 V. ~$ L) |& q
- /*中断处理顶半部*/
6 c% y! q0 c: Z/ _# y3 Y0 S - irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)
$ S# s0 G9 I; w u* I. L - {% `2 P: r% n+ B/ I. N- E
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
2 H$ K+ }# ~* }, u" A1 F$ h d% ?6 z - volatile Buffer_Type *next_read;) d$ |8 K7 ?, D0 a+ N. a' U9 h
- //如果DSP数据已经ready8 j7 I# X+ l/ ?3 Z7 l
- if(*(res_buff.cur_buffer->data_ready) == 1)
' b e( j T9 w" h- p# Q& f" J - {
/ ~$ Y' m/ p% W. S1 L - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer
4 W) P$ Z# x, m" K, G a" v; M - {8 T" n% S; |/ l
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer. }. X" d l, A" n' `, c9 y( `
- //printk(KERN_ALERT"read ping\n");+ F6 w* p" z) @- L8 o* `2 e
- }; r+ I% G" d$ u3 h0 O9 |- g
- else
* J/ A0 F( x. ? - {- w. |4 x8 z1 P" l: H
- next_read = &res_buff.ping_buffer;//下一次中断读ping buffer. x; i2 q6 a2 C9 D. a
- //printk(KERN_ALERT"read pong\n");: B1 b+ G- F) I. N6 U# q
- }
, m+ b/ ?% Q& z - *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer
$ s; W7 {& v" N* Z* } - //将数据插入链队列
+ c' k1 ^; |" Q2 q. n' s - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);
2 ~" j! S {7 f7 ~* S - //标识位都重置( e, s4 c5 Z7 ~& u. k
- *(res_buff.cur_buffer->data_ready) = 0;
: o2 l% C" b/ K. G3 X - *(res_buff.cur_buffer->data_size) = 0;
4 ]2 C. n5 l6 L" D, P2 O" B - res_buff.cur_buffer = next_read;
: Q) o( i5 f @8 U: N - }
4 A' Q, `( O, K8 `' { - //清楚中断标识6 e7 y- Y3 A0 m! Z' l5 `
- *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status; {7 e, Z4 w+ D) b" f
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部
' Q" z: l/ {) n, A( h
4 @! H' O5 G2 {' f( k F* Z, Z1 ~7 L
7 R3 G8 Y4 U: @) H% s9 u- return IRQ_HANDLED;% e( v, @) B7 g( X
- $ }5 l @" a$ l, R. A
- }
, M# C( {5 B0 [8 Y" V" ? - : N7 B( n- b. E0 L
- //文件打开函数$ b& C7 {: ]8 \) h! _2 ~* z
- static int protocol_open(struct inode *inode, struct file *file)
8 s8 |6 P0 }9 I6 m& K* K% ^% w; k1 ]# X5 d - {0 K( T1 d; f9 N8 @' p
- int result = 0;
8 t* t8 P2 O" f - if(!atomic_dec_and_test(&dev_available))& @3 c& |6 ~, z7 c2 Q* ]
- {
0 j+ B. ~$ X# t2 v: i - atomic_inc(&dev_available);. L; g* T: P) x3 B- V
- return -EBUSY;//设备已经被打开
0 ?, R; G1 K3 I - }
4 u( f1 y& e# t4 G4 Y4 o - printk (KERN_ALERT "\nprotrol driver open\n");
& W" P) y c3 j3 U. n) Q - return 0;8 A5 @* k: R% c* i/ j
- }1 L1 A; s, O1 |* ~* A% t/ i" H
* O. Z+ f; [% x$ V- //文件释放函数
' D M2 \% U$ n& O# E+ K - static int protocol_release(struct inode *inode, struct file *filp)" u K. F" a5 w4 V# Z
- {: H; R- J) y- k8 q7 W
- atomic_inc(&dev_available);//释放设备,原子变量加1 e- A, F+ |" m& c
- printk (KERN_ALERT "device released\n");
2 A r* \4 P% i- {( l0 K3 P0 g - return 0;
2 G& d% z1 t4 V' j4 X" E0 r - }) [% {4 `; _$ s* j: j
- + c( d* t4 g4 X" i1 Y- Z5 I! N0 C" X
- //文件读函数5 p$ H1 J$ @0 @
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)
0 F5 w. Q. X {3 \+ }( h& ] - {
/ u, e# `/ G8 p7 c% q - int ret = 0;
/ t% s8 H! }- N5 x; @+ `; b - //定义等待队列
- ?. x" i8 a3 W' g - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列- t6 ]1 a: m' l3 o
- add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
6 ?1 M/ x$ e: d/ C" { - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据' `8 r0 ~0 |& V* [& h5 L
- {
- H( E* a% L& @; r; t( @$ m& f - //printk(KERN_ALERT"\nbuffer no data\n");
' @! R! {6 |4 p9 U2 j5 x - //如果是非阻塞方式读取,则直接跳出 K; a& ^- g9 s. `* ]" A, W
- if(filp->f_flags & O_NONBLOCK)0 i# G. @" i, w6 `
- {
' C" Z& L/ Z7 l, V2 Z3 Y - ret = -EAGAIN;7 G& Y3 b6 Y5 T! U' z5 }) s
- goto out;+ ~+ e/ q1 {8 x, f' ?
- }
- X9 G' k6 ?, C1 ` L3 V# l' A3 n8 r - //阻塞当前进程,放弃cpu资源
1 H% A5 ^8 m6 | - read_quest = 1;
( S P% \7 j8 O1 ]; L' a - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠
1 `& K% A5 Q! W( M$ x - schedule();//调度其他进程运行6 @. y: O# w' |. x* ~. U, H+ n
- if(signal_pending(current))' T" ^: ~* _0 q/ `+ P+ T
- {. D3 G8 `8 d0 y$ J0 ?
- //如果是因为信号被唤醒,则返回到系统调用之前的地方' t4 n5 c: @; v& o& B" h
- ret = -ERESTARTSYS;- Q' y0 }4 D, f1 Y; a
- goto out;
) @! L5 h8 u( i, u1 a - }
2 ~' b7 i- o" W/ r8 v9 @! A" U - }/ l4 s6 c0 d+ f+ A
- //将数据拷贝到用户空间' s# B2 [* A! z2 D8 k7 e/ R
- ret = k_linkQueue_getData(&queue, dst);
. S7 ?2 y% j! X: Q, k; @1 U4 z9 E1 ~ - if(ret == 0)
; U9 u* i4 g& W- ` - {
2 `# L/ f( W% t3 [2 w - //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);; O* d0 Z. y, Z, y" t" P
- }
/ w) ~# Z: ~' {, y7 [8 d* e - out:
3 z. s% ^( k8 H& \) q" f \ - remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列/ G/ ~! u' `: ^) l
- set_current_state(TASK_RUNNING);//设置当前进程为运行状态
, y! R2 U- z% e y* X1 _. u9 l% ? - return ret;
2 x1 |2 S/ r/ A3 d - }2 {1 r, e4 C. G# k& B( N
- / e p* G; A4 o9 O
- % V! T" P+ W; o& [; |8 S
- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)
) v2 C4 Q1 m! p0 ?) ]' d - {
- H# {4 R1 j" R# c9 o" B - return 0;* }$ ^1 y: ]( c' x9 X. c
- }
- ?# q5 n# ~# k - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行
! V) T$ z9 n0 F: P0 j) _ - open()、release()、ioctl()协同调用时被调用*/( u, b8 z& F3 C% I6 H# V% K$ x$ B
- static const struct file_operations protocol_fops =
9 j' `& e7 e: K6 z4 t - { y; U* f" u8 k
- .owner = THIS_MODULE,- V6 m+ ^$ G1 e) b0 V
- .open = protocol_open,( p9 E7 n) i8 a& p1 m ~; F' ]
- .release = protocol_release," ^( g8 {5 N5 t8 H/ b
- .read = protocol_read,4 l6 Z1 D4 S; I6 Z4 s; u0 B
- // .write = protocol_write,3 ^0 a: l+ W# N' {9 R0 X
- .unlocked_ioctl=protocol_ioctl,
~. C; C4 P7 R% F( y1 b - };. ~; G- T* P: o9 v3 q/ A+ M
- ( H) E) }; d, `3 N
- /*设备驱动模块加载函数*/
. B) o' k0 x; W3 P - int __init protocol_init(void)
- x, K! c) S4 ] b! [/ }" Z - {6 {) `5 q& \4 j; v( c) T6 N8 m+ f
- int ret = 0;
' m4 ^3 F5 X* ^0 p& P - int result = 0;
/ k2 H; |& z8 y) c4 c9 O - //申请注册设备号(动态)) w0 K! x9 C+ K6 j) ?
- ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); ' {5 R* ?9 P6 F" c
- if(ret < 0)2 b! E% L" u! v4 A, M0 A' Q
- {0 _) _" _; e: `: H8 u
- printk(KERN_EMERG "alloc_chrdev_region failed\n");
! T9 p q' e1 b, [+ E# q/ s* c' W - return 0;8 h" q$ e" i. I: J/ V7 h# k
- }; ~: a( p, @' u5 ~' }
- //分配cdev6 O3 O! h: f" j
- protocol_cdev = cdev_alloc();
/ [7 i) i7 G# G1 i - if(protocol_cdev == NULL)
! q% ^8 O; T- _' L5 _) X - {
: x! R2 x3 S- O% K7 V - printk(KERN_EMERG "Cannot alloc cdev\n");
6 J, i% W( Z) b4 L2 g) \ - return 0;5 E$ ~. @* _5 @; A
- }4 a; @/ _/ V0 L7 E
- //初始化cdev. U U& T. p u9 W' v0 ~7 f5 H
- cdev_init(protocol_cdev,&protocol_fops);
7 [: \1 c( d' X B3 P - protocol_cdev->owner=THIS_MODULE;
# h7 \0 y/ Y* S5 g - //注册cdev) G# @ G8 R" g: V+ A9 c8 q: U
- cdev_add(protocol_cdev, protocol_dev_no, 1);
7 F9 J/ d% U' {. y - //创建一个类
) q2 O; `# I$ u; V j' V0 U) G - protocol_class = class_create(THIS_MODULE, DEVICE_NAME);" J# D: u f9 N
- //创建设备节点9 I; ~, G! v. Y, ]* L3 f4 R" C
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);( c1 q" E% v* R. ^9 G8 V, k
-
1 f, S1 v+ ?) C( F -
4 F7 S( w# o) W" r) ?2 M - //申请链式循环队列作为缓冲区DSP数据帧的缓冲区
% T) \$ v! m* Z: S- i. ^; h - k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区
2 w. [' W5 s) v6 A2 [7 a/ e9 s
, |( I" t1 X$ o) m; @: R; ~- //映射ARM的核间通讯寄存器
5 U) m$ r# v1 o, J2 P7 E6 q - R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);5 i' h0 \4 l* }
- R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);5 s& a& P" o' l4 }; m3 f, M
- //将物理地址映射到内核空间2 }1 r4 |5 G1 c7 ] s
- mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);
. X- U* Y% W( |* M& s - //共享内存初始化: R, c1 k. x8 {7 Z0 i0 R" O$ T3 d
- SHM_ARM_Init((unsigned char *)mem_base);8 Y- E1 | s4 w+ u1 S" z/ }
- /*申请中断*/
0 g2 {5 I& _6 B4 Z- l
1 r% o2 D3 k* o q- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);9 ] S3 e. Q4 u# l) R! ?1 }) J
- if(result != 0)
/ T$ j t; q* a$ R8 W! q& E - {0 |. o1 n3 Y m. I& N
- if(result == -EINVAL)$ d: s( K: D$ A8 z# Q6 y
- {
+ m" S- T& \: Z! J# J8 L0 R1 T& g - printk(KERN_ALERT "irq request err:-EINVAL\n");
: | r3 i" u( G& m, m - }
% o% ]( a# Y& `3 E* l+ j: X( e. F - else if(result == -EBUSY)
8 f5 x7 V3 J3 B - {
% q9 _6 Q- d3 T5 B2 M% l# \1 ^ - printk(KERN_ALERT "irq request err:--EBUSY\n");* o: H" ]: q/ `- ]0 a1 d G
- }% i; m6 T& U$ K6 L B
- else
5 R; i& ~6 e4 t7 P! @ - {% i8 H8 {$ G; V3 j% E6 @1 F
- printk(KERN_ALERT "irq request err: unknown\n");
5 t, \4 J; Y" G! o( m - }
. x7 A4 B1 V4 F; U9 y9 E1 [1 d - return result;
! Q! J" \' }4 v! s- w" n - }
% D4 \# i" {$ |. _ - return 0;
# J6 X9 j w2 @- y5 \: i' c - }
5 G4 \) b# n8 Y0 V) H5 u: p
, j/ I; O9 Y! A# G, O- /*设备驱动模块卸载函数*/+ d; h) s5 O$ r" |( i
- void __exit protocol_exit(void)$ W1 ~8 ~$ y$ q( o2 E) L
- {8 u% h* @% D8 N x) {7 L' R% }8 W
- /*释放中断*/
+ g" ?5 F8 d3 [. s' `$ G, Y - free_irq(IRQ_DA8XX_CHIPINT0, NULL);$ O7 Z* T: h' a+ s4 @
- //释放帧缓冲的内存& }6 v+ |4 y' @% A% Z
- k_linkQueue_release(&queue);
7 L& t, X: W, o+ e - //释放寄存器映射
4 w0 t: B- ]+ _# z6 G - iounmap(R_CHIPSIG);
D- Z8 L/ k3 [- n' u& n - iounmap(R_CHIPSIG_CLR);
4 Q/ `& \% C# j- _2 [ - cdev_del(protocol_cdev); //删除cdev
/ g6 o( {7 Z4 M% y9 w1 _, i9 a - unregister_chrdev_region(protocol_dev_no, 1); //注销设备号$ W* _, k0 z8 O, `- f. C) R
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
9 {' b2 Z! Y" g* {# { - class_destroy(protocol_class); //销毁设备类$ b n, m3 u4 d2 b
- printk(KERN_ALERT "exit success\n");
$ \8 u8 I2 _7 L
+ C/ B0 M2 Q" [0 f4 v. R- }8 s# ~9 O) ]! v8 `: W. l2 V
- //驱动其他部分省略
复制代码 + ~ u) u2 v: k, C4 @& M9 K
+ ?) Q; u8 c/ q! j. z2 s
|