本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑
5 ]6 B. g' C# J( E( C" y# @$ m
: C+ S9 F1 \ e3 c2 L0 R; ^项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略
) o3 R* E" S: S
. d. H; p$ q2 i- //引入其他模块函数和变量& \4 o; N- `. E' | X
- extern Ping_Pong_Buffer res_buff;
5 l$ }. ^4 f i, i: @3 \
5 ^& o7 p& m4 H- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列
: e* C+ F& y) o/ s- i! T( R - extern void k_linkQueue_release(linkQueue *queue);//释放链队列1 N3 d# x+ }5 `/ P; O) Y$ q
- extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据 e' s; f0 ]. L; o& ~9 m6 [
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据! i' W4 {) N# Q1 |/ I2 c9 P
- + |7 c! F9 [3 W, }' [" L) [0 N; y
- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化1 h i9 ^& l" C* W I; v, k s& O
. Z1 D$ h7 s( R* Y% C- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1; C8 u; R) L0 |# C1 j, F
- //设置主从设备号
, y- C% e j$ X. q: ? - #define PROTOCOL_MAJOR 1
7 J; W7 e5 L# m/ @4 T5 \) X - #define PROTOCOL_MINOR 0
- A# Z6 [1 h( ~ A" W
- l c- e/ D5 }9 e$ E2 r3 j& X
, A' b( ^ {. x D3 ]' ^- 8 f" T+ S" w( z0 l- M3 A" [1 a* Y
- //定义设备驱动的名字或设备节点的名字) F' j0 [' [1 @& U% a$ V- W
- #define DEVICE_NAME "protocol_driver"3 v- o% Y) k7 C/ W7 q" ^1 ^& q
" V3 y4 Y- }3 ?/ @ K: s2 G
/ c8 \$ i m( s- //定义全局的循环队列作为数据缓冲区
/ [' h% l4 o9 q0 b8 J1 j1 j6 i0 r - k_linkQueue queue;6 [( }. T$ I% s$ P5 l. g" M
- 1 \, U7 \$ b) d; e7 x7 B
- //寄存器地址映射全局变量1 f b/ U( ?; `/ |
- unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器. A# B& |% E3 _+ h
- unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器, |7 @+ ^# d. @7 ^
- 3 g1 q a X# n2 m
- //物理内存映射全局变量$ j" g5 j+ y- Y# u% V7 f, F* Y
- volatile void *mem_base = NULL;! O$ y7 Z: ^; I% _+ D; O
- volatile unsigned char *cur_buf_ptr = NULL;
+ V, \2 ^6 N9 } - volatile unsigned char *data_ready_ptr = NULL;( m# B9 p6 o( Q) \ M5 Z
- 8 \' R' _ T# N
- 7 o8 {' D. j" v2 W
+ s! I$ ~- H* o4 ?3 H- //定义读数据等待队列头,IO阻塞% d1 W% P/ N+ N" ~% t
- DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);3 S; R% H8 h; b5 x d
- c) i' D* B0 [+ J
- //定义原子变量
& L$ A1 }$ k- w0 c" Q+ o - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备, H0 c Q) ^! ^7 |3 E8 Z0 ]2 J
( T8 B/ ?$ x. u l2 A% z( i8 P
6 Q, ]# ^ n, J' C5 }- //定义设备类" O" T$ W" S ^0 a6 r/ N) f
- static struct class *protocol_class;) @) _" i! {# q0 r
- struct cdev *protocol_cdev;; p% W' T% S& O c- O! a( C
- dev_t protocol_dev_no;# R5 t( E7 @2 L( ^& e" y
5 j% t# w8 A2 v. V' j" h- M- /*定义tasklet和声明底半部函数并关联*/$ Y+ M# ^/ |: ?0 ~$ r6 t
- void read_data_tasklet(unsigned long);7 b* d- t5 t8 D
/ ?) d0 S; s( A- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);/ M- R6 K4 D$ P4 a- _) w6 t
- //将CHIPINT0_tasklet与read_data绑定,传入参数0
7 p- t1 f3 M5 u2 u% Q8 f5 f
& `: h! t( L* V) ]$ C) s- /*中断处理底半部, 拷贝内存*/
& p+ D3 I) J1 {$ m3 G2 J& e - void read_data(unsigned long a)+ N" Z6 r* s' N) e9 T2 `" q/ N/ R
- {9 d5 Q5 D8 u# I9 A" y+ T7 C7 Q
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1! c v, p! K# O# T0 Y* g
- {1 |$ S$ T- R' e& I5 ]1 e
- read_quest = 0; X' I c: e' Q2 G! J }
- wake_up_interruptible(&wait_queue_head);//唤醒读等待队列7 D# b% P( w* |1 T7 k
- }* S8 l" E; o% l1 e- _" y8 U+ \8 p d
# s1 M# Y3 M# }- }3 e5 t1 J; P' N7 U: _; B. o8 l
- - f8 Y3 P5 m J
- /*中断处理顶半部*/" f: ^) m7 W; b E* a$ N9 I+ S6 s
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)
1 h5 L+ t5 Z; }; d8 n* h' ~ - {
1 m8 a$ D' A/ N/ V% @5 w* J* H - //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
/ X, ^) m4 H. D! E/ N) ]9 y& t - volatile Buffer_Type *next_read;
% @/ K* ? Z8 q0 ~6 Y6 o - //如果DSP数据已经ready
w' f( S9 c" M; [: z - if(*(res_buff.cur_buffer->data_ready) == 1)* ~* k- m* G5 h. C+ k; c: k4 H
- {
, r, a) k4 @) n3 M4 E8 N7 I - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer
5 ]/ a3 O1 X$ A1 P/ a+ v: m+ O - {( E, L9 G% K- [" b* O7 U8 g/ F
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer, A" k) {7 _7 G" K, v
- //printk(KERN_ALERT"read ping\n");% i1 T& ]* r9 c% |
- }& r+ p: y3 F3 D0 }/ A
- else
8 M2 e N2 I0 E j* V0 ]: T8 T - {
. v4 N Y+ r; p9 y - next_read = &res_buff.ping_buffer;//下一次中断读ping buffer( Y) t& U5 k- m9 |( `
- //printk(KERN_ALERT"read pong\n");( W$ S3 Q7 m6 ~: c' f3 s# t
- }
% [) U& l7 J; Y e: m2 E& X0 w - *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer8 V2 q- |; n, R1 B' o0 y2 W
- //将数据插入链队列
; J) k5 z, O# n' n% G; y - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);
2 J3 N+ Y1 ^! b1 i( | - //标识位都重置" `- [# h! W$ j# E
- *(res_buff.cur_buffer->data_ready) = 0;9 F7 {" j6 ?/ u5 E; ~; }
- *(res_buff.cur_buffer->data_size) = 0;
1 k' M6 j6 D( ?. ~$ D1 _% V4 R - res_buff.cur_buffer = next_read;
5 ?1 _) C1 O E' m# { - }, l: N6 ^$ J# ^; F% _: G
- //清楚中断标识
+ q- g% F: d s. } - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status4 P g0 G) M$ D* a" M
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部
' p$ x" b- d/ ^# C9 ~
% {3 s& B0 ]0 k3 b( v
1 V' `6 i G& L6 D. R- return IRQ_HANDLED;
9 E. i h6 j/ p& L) U0 A - % k F f- ~, }0 y4 Z
- }7 s) l. E, |. r. g3 d( i9 r& y
- 1 E! [# k2 f( M2 O) U
- //文件打开函数
. N" p2 e0 ?4 Z0 a' V& w6 w( `4 K9 t - static int protocol_open(struct inode *inode, struct file *file)5 N0 n* ^! [! Z" {0 Y' C7 f
- {
N) d- F( ]5 s/ E! c - int result = 0;
) W! R6 k7 C5 x: P. h! U/ E M) v - if(!atomic_dec_and_test(&dev_available))
9 Q# w2 \! a+ W1 { - {4 ^ S1 m% X- l. g& l
- atomic_inc(&dev_available);6 X9 m0 ~3 J( R. F( i, ~5 ?; z
- return -EBUSY;//设备已经被打开
. w6 {* T* A5 I/ K( [7 H1 D - }
3 x l* |% d, n0 T8 [: j7 u+ r - printk (KERN_ALERT "\nprotrol driver open\n");+ p6 l9 l8 C1 F5 O# @3 ?
- return 0;
$ n$ \' \" p% o7 v" k - }
. v9 L$ |/ ^: v7 a! h- ? - 0 k( z$ v5 u+ ]
- //文件释放函数
+ d6 F S3 [5 W' L( }! q - static int protocol_release(struct inode *inode, struct file *filp)
( T) |' @ v0 U' n* o - {
& Z1 @- A" |, |' Y% P+ P - atomic_inc(&dev_available);//释放设备,原子变量加1
, x, O+ Q, v* S, g - printk (KERN_ALERT "device released\n");# J1 H* s2 D& C: f) y+ u [: M0 F
- return 0;
0 ?* o) u- J7 h2 i) A0 O; u - }, L W6 K6 y3 j9 z; l# @/ L
6 a! t7 J# q4 F( H6 a- //文件读函数9 h% Z$ d" b: W: Y
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)
/ k! ?$ x' D0 _ - {& @! F& F' E0 b! e s2 _) J
- int ret = 0;* Z" N& z* \2 M7 W( @0 m8 W
- //定义等待队列
2 q3 _3 Z2 g; E - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列! `2 H" g) S3 P. y* \7 w, N
- add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列$ ^2 ~( [: Z0 D D5 `' F
- if(queue.remainNumber == queue.blockNumber)//当前buffer没数据) j2 o2 w: O' y; Y
- {/ P7 k! C- o) G2 G
- //printk(KERN_ALERT"\nbuffer no data\n");
/ I- ?% R S2 ?- k6 X - //如果是非阻塞方式读取,则直接跳出, @) a' l) L' k' n7 a" t
- if(filp->f_flags & O_NONBLOCK)
7 X3 q2 h b1 @9 U - {
" l, q0 }; J" N1 ?; p - ret = -EAGAIN;
, W9 j7 L' i3 k' q! z - goto out;( H6 j! k% A8 g, o
- }
6 P% h" f% }) ^/ \& h - //阻塞当前进程,放弃cpu资源
4 P' L8 J" H2 y: O2 h - read_quest = 1;9 J( Y, t2 t* Y. s9 d1 g
- __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠
3 j" \! s& t0 H8 g9 ~9 ~3 N. T4 d3 J - schedule();//调度其他进程运行
# U* D) T" D S8 j( i - if(signal_pending(current))) a7 C/ {6 \" d" A/ F2 t$ A x
- {
) F# k; _4 o- A& I - //如果是因为信号被唤醒,则返回到系统调用之前的地方" G: ]- D# D- ?5 T" H* e# \+ m# `
- ret = -ERESTARTSYS;" {5 j* ?$ d2 a2 K% }( f8 K
- goto out;
! s5 K' W! X( q" O7 H" s1 U - }* j9 ^, u7 R M% b* N" m% Y
- }( D! z# I& A5 |6 J$ B" w
- //将数据拷贝到用户空间
, L4 G% y) E4 N Y. ~0 V2 H1 q% j - ret = k_linkQueue_getData(&queue, dst);% _8 p5 d6 `: x& b5 n1 ~9 W
- if(ret == 0)5 U2 v- t4 f' M/ T. u( E8 v' z
- {
# z/ S d2 P& H2 m+ g - //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
. I2 J$ \/ b1 M) x$ J - }7 Y' d2 t5 i2 L7 ]" H% _) a
- out:- s, y. c# j$ L' w9 q) g. E, r
- remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列, A& t; x- L) i- g/ A7 e9 s5 W4 M
- set_current_state(TASK_RUNNING);//设置当前进程为运行状态 N) h+ w, z" F0 z$ R* [4 z
- return ret;
# a7 d" j4 v- J* l& N2 u2 d" R - }
. N$ @0 ^' I' E# I& T. C, x - ' z7 H. l# R1 r& Z
/ Y% K" f: O4 Z# n h. A2 n- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)
" k/ p, f$ U6 B" A - {
z. B# R( y1 z% p - return 0;
/ k5 ?8 a a+ C; q/ F: e) p - }
, V5 l$ f3 y& J - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行# ?7 Q2 ~- M8 z
- open()、release()、ioctl()协同调用时被调用*/, @6 B3 T' R& g
- static const struct file_operations protocol_fops =( a4 \8 s% \( v% c* p, k
- {
1 i5 G7 t0 p$ Z/ f - .owner = THIS_MODULE,6 m) `% g" h: z+ d1 A
- .open = protocol_open,
: y+ T& ~* R3 ]4 R) e% m - .release = protocol_release,) j" g9 u5 |0 ?8 i: x1 B0 S
- .read = protocol_read,
1 ^% x1 ~1 i, w1 q+ O% b9 a - // .write = protocol_write,* \6 y) B. p/ R- n( Q9 K( u3 K- n# A
- .unlocked_ioctl=protocol_ioctl,
" T2 c" q: w; B* Z - };, o- w. [2 y( z# l( \
( v* h L9 |- N: h+ I- K6 U* U- /*设备驱动模块加载函数*/
. r6 P2 E# R4 b7 Z. m - int __init protocol_init(void). X% M: |* s/ O
- {1 M" C; Y6 g( i C* t8 ^
- int ret = 0;
, A8 h# {: g t% _" N/ ~ - int result = 0;
$ \- i4 ^6 ?( A - //申请注册设备号(动态)
% I I& G7 C5 N. x- m - ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); $ \6 a2 N4 i5 D" ~2 u2 \" i
- if(ret < 0)
9 t( }8 e2 F" ^# U, i* B1 F - {8 H5 r* x- ?8 p" m1 R) H
- printk(KERN_EMERG "alloc_chrdev_region failed\n");
8 m* ?" d4 k; u7 C - return 0;
9 ^: W" s2 l* \ - }1 l- T( W( c6 ]8 R, A+ U
- //分配cdev
# ?/ Y' w1 v9 ?& s - protocol_cdev = cdev_alloc();, A7 N, k# S* F) f$ p* U- t. S
- if(protocol_cdev == NULL)" X% `7 T9 K9 ?, b6 q
- {
3 J. d0 u0 s$ {' l' ^% Q0 n9 B: F$ t - printk(KERN_EMERG "Cannot alloc cdev\n");
% n- p) `1 q5 {' J - return 0;
8 Q3 v2 w5 ?# C c4 p - }
1 E$ R. j0 w# R3 { - //初始化cdev* ?5 r4 W- a& e5 O7 [
- cdev_init(protocol_cdev,&protocol_fops);
. I$ I3 k- @4 z - protocol_cdev->owner=THIS_MODULE;
, G6 L3 ^: p8 j& C+ m7 e - //注册cdev% q4 G2 ]8 H1 E% Y; L H5 B
- cdev_add(protocol_cdev, protocol_dev_no, 1);
" I! k8 w |) g q - //创建一个类
& p0 ]3 q5 q. ]/ N' `; u - protocol_class = class_create(THIS_MODULE, DEVICE_NAME);0 C1 s i, ]0 ~, h; A3 K( F
- //创建设备节点% m$ W3 k" r. M7 r. [: B$ M H
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);
; d+ ]8 `/ n0 i, H5 n; n7 Q! S( B - 3 u4 I2 v: Z$ m: a, \, M, I6 R
- 2 g4 `+ ~& w8 v& ^0 t- C, _
- //申请链式循环队列作为缓冲区DSP数据帧的缓冲区
& N; m% J4 a! q9 c0 ?$ a. W - k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区
9 x; k/ R9 j& U5 x9 Z* n
6 B; K+ t4 j1 S1 J- u* U- //映射ARM的核间通讯寄存器5 l7 r3 W$ h7 F- V
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);; F/ _, ]' U$ J7 c8 o8 k7 i
- R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);
) ~6 }) Y% M8 v - //将物理地址映射到内核空间
2 ^0 |& e' x% s& A5 b. G# n - mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);
, S' N+ M" @, M! N4 r5 d8 E - //共享内存初始化
! T- ~ G8 ]& [# T) ] L( ^! l - SHM_ARM_Init((unsigned char *)mem_base);1 u9 r% S$ m% ?# ^
- /*申请中断*/
# N$ f( X' S4 _+ Q3 H3 X - {/ ?( }/ L1 @2 Q
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);
j+ o% Y8 a( U - if(result != 0)+ D# A( E* ^% {2 Z- Y
- {
7 P$ V& d* m1 S% V' h( V; _6 i - if(result == -EINVAL)
% |0 t# E' {# K( _, P1 O" u - {
+ ], J$ i0 k4 U$ _( R8 y - printk(KERN_ALERT "irq request err:-EINVAL\n");
/ S( P8 Q# b) k$ x1 l9 I B! j - }
; H- V1 Z( Z* e6 K. ~. e/ w - else if(result == -EBUSY)( K) Z8 ^2 b% ]
- {
1 k2 h, a/ n' g, n: i, n - printk(KERN_ALERT "irq request err:--EBUSY\n");
% w2 m5 R. a. ?& x6 B+ |1 m3 b3 _ - }
6 {7 W ~# W% `% u: y) n% y - else
. S+ @+ N- U! B0 U$ V - {3 Y# _: Y7 x( @( f
- printk(KERN_ALERT "irq request err: unknown\n");
0 _* @; V. V" p) D" C# ~ - }
7 R" u: L' G) u( R8 h& Z - return result;
' a) i5 b6 n$ U9 M - }( c5 r! n% c- [; R' W2 F
- return 0;
! L" k' A9 K9 V! j- K# h1 n - }
' y* O" {) d7 w9 L- A. E
* O/ w3 A! c5 b! i- /*设备驱动模块卸载函数*/
. O0 z) ]" N# [0 `' N1 h - void __exit protocol_exit(void)
4 B% U, F5 t1 q# t# P. k! o1 B - {4 m8 s2 _2 @5 t# W
- /*释放中断*/" j( J; B7 x( B9 Z( a
- free_irq(IRQ_DA8XX_CHIPINT0, NULL);
8 \/ n) @4 \0 L9 v+ Z9 I - //释放帧缓冲的内存2 R5 V8 {4 K" l! N/ a" q
- k_linkQueue_release(&queue);' E0 f' u7 k) y8 J8 R
- //释放寄存器映射0 M* w( |, [' s- \' U! F
- iounmap(R_CHIPSIG);
( h: [# N; w: q3 k9 R+ W8 a - iounmap(R_CHIPSIG_CLR);( [% D# h% ?5 p8 R4 @6 P
- cdev_del(protocol_cdev); //删除cdev* S8 i f1 s2 B! C' }& z) _
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号+ y6 T0 q8 _ l( P& _: I% ~
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点- J0 P2 Y0 l3 f$ o6 P2 E& x1 G
- class_destroy(protocol_class); //销毁设备类
2 d7 s; @6 { v- f - printk(KERN_ALERT "exit success\n");! B1 D* V$ X9 r2 q y. V9 m% g
- q4 T5 U/ p* i0 x; W, H8 K. N- }
/ ~ d4 K. Q8 b; {/ j4 l6 c4 a& n - //驱动其他部分省略
复制代码
% R T: r; j2 h8 k/ r& u3 ~% P) c8 A# r; p0 F# ]% E$ P
|