本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑
" b4 F$ ~, s1 g/ L* u' N; w
; k$ @; \3 _$ {5 Z& 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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略
3 R; B" l* s$ S) g3 V; h' ~ - # d% U6 W0 x" ?9 ], B6 @. P1 p& m
- //引入其他模块函数和变量
: x3 D" h, f& h" U4 } - extern Ping_Pong_Buffer res_buff;
+ _$ u& Z5 Y+ b2 U9 D - : m: A" L$ z& |6 K
- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列
6 I( d; f8 v; l- B) ? - extern void k_linkQueue_release(linkQueue *queue);//释放链队列
+ N0 a) o0 L+ G - extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据
" a7 z+ Z/ L& q( u- [: x5 s# o' f - extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据1 C! I* v& @# c0 h
2 I" j( v+ Q3 o) J+ z) h- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化, A! L( F- H& Y w- q
& L; A3 J7 h2 R- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1& X- X, z# J+ H o F5 N6 S( ^& p
- //设置主从设备号
6 l9 s" f" @+ Q: v9 }% E - #define PROTOCOL_MAJOR 1
- c8 E/ \. q1 N9 d% a# I - #define PROTOCOL_MINOR 0- V& ]0 x! ?+ t+ L
- & f# ~% O/ c q4 m9 y/ a/ G
- / w' c _) ^8 i, h1 Q
- # a' r; D! N( L2 S: p& K3 w% R
- //定义设备驱动的名字或设备节点的名字
/ C( w* s2 a# h - #define DEVICE_NAME "protocol_driver"
8 b* I, w J6 x' _) ?
- t( I( a8 [! r" @3 j$ V) v ~# U
' L8 h3 z D7 E# j1 o# P# A' C( d" H- //定义全局的循环队列作为数据缓冲区
7 s% v2 B' c9 H& R- F, X. D' y g - k_linkQueue queue;: P' I8 G, X8 v1 J% D8 |
- ) p4 F7 w! }0 R; H7 g" ^
- //寄存器地址映射全局变量9 | k2 v; M) V3 p/ x. ~
- unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器
7 _' Y3 L5 T8 ~& H9 V w3 r: U+ P - unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器: y7 r7 l9 U- }' ]9 J' p6 R
- % {* d' w* D8 T: E7 j7 V6 W6 j2 I2 o7 P
- //物理内存映射全局变量
/ f( D/ m2 N B1 P: _+ f - volatile void *mem_base = NULL;7 _. M( B3 C3 R! ]( y9 Q
- volatile unsigned char *cur_buf_ptr = NULL;/ s1 R' y: H0 z: A* A
- volatile unsigned char *data_ready_ptr = NULL;
. s) W8 L3 D. W! X) a) f0 [
0 T k! Z; v+ j3 B0 l0 t
& @5 H' w/ ~+ l# u* ^1 k. r
0 U' d6 Y/ r |/ I- //定义读数据等待队列头,IO阻塞+ `7 ?% S9 I- [7 N9 E( Y
- DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);5 `' I- d4 m( j1 h* [
- - C* x, w* l) p/ c W- ^
- //定义原子变量$ e+ G2 p: Q: \/ w' L
- static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备
8 w$ M/ O$ e6 P$ b* y - 2 ?' H& u1 o6 Y$ l& `- j
- |# }: d9 U0 |( ?' o" M
- //定义设备类& h2 L! d3 v; a$ c1 G$ b
- static struct class *protocol_class;
% e$ J1 k+ i2 o - struct cdev *protocol_cdev;
6 \9 b" D1 }! ? - dev_t protocol_dev_no;
* b% B) S8 {( f7 g* X F4 \, r" d - 7 c6 s" \# o, x8 a: T' L' g+ K
- /*定义tasklet和声明底半部函数并关联*/
! @4 ]; G) a5 p - void read_data_tasklet(unsigned long);
V5 A9 m) t, k# m- { - 0 `# m, k Q- e+ _
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
5 x/ D' n9 R3 v: q8 u6 l' H. H; Y- u6 J6 w - //将CHIPINT0_tasklet与read_data绑定,传入参数0
* J3 k2 o- j7 t - ( W: A+ _, }* P! U3 L& e/ E+ G
- /*中断处理底半部, 拷贝内存*/
4 g) \& p* ^8 `8 b; L; f - void read_data(unsigned long a)
* h! n8 P+ i2 }$ {4 H. c4 z - {- ]( @& m1 C, [. n; V+ u2 Z
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为17 w! X' D& }: `" r# W. X
- {/ U5 B: l2 v0 ]* ~% ?
- read_quest = 0;& Q% {; Q" y9 b( ]; s2 f$ c
- wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
+ d, O+ s+ q( E4 p8 `7 ]6 e. K0 W - }
9 S' `4 o, D$ {% D5 G7 f - , M* m& R& Z9 S1 k, T
- }. D/ ?8 Y. u8 I6 a
4 q; n. D0 ~; Q' s! g& P& w- /*中断处理顶半部*/
9 K* t# y) Z& i - irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)
5 t9 I4 m) ~4 z$ H5 {4 H - { K" y- W4 G6 H
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
2 A5 C) P& f k4 r5 q - volatile Buffer_Type *next_read;
- r6 K( T0 |# O# p - //如果DSP数据已经ready
t8 p- r/ O5 a2 ~ - if(*(res_buff.cur_buffer->data_ready) == 1)% _" J- n" _9 j9 B
- {
2 C/ y; U' K2 f6 z3 w - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer/ U, ?7 G+ ]; L4 B. X, @
- {
& {1 N' u5 A! l+ K0 `. d4 m - next_read = &res_buff.pong_buffer;//下一次中断读pong buffer, i4 M* y$ Q- u6 L) F- Z
- //printk(KERN_ALERT"read ping\n");
3 x' y7 r8 U/ F! \: l - }; W! h0 l G& F
- else) ?: }! |9 g" L+ B" w2 S. {
- {" s2 j8 {* K* X
- next_read = &res_buff.ping_buffer;//下一次中断读ping buffer* l/ s: u# ?4 ^% i: y$ {! f/ B }
- //printk(KERN_ALERT"read pong\n");! N: f/ B m( t9 R* V K( q
- } R I' ~) g- k$ X/ @1 f" x
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer
0 z5 z7 o) h2 S: B5 w6 h/ B' H: e - //将数据插入链队列
3 C1 ?( y# P' t0 Z# l - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);8 ]: A. R$ o/ E8 N0 R
- //标识位都重置+ q( z' D1 f+ l/ {* w# X
- *(res_buff.cur_buffer->data_ready) = 0;3 l3 i5 e1 K) I1 u
- *(res_buff.cur_buffer->data_size) = 0;
( c4 {% t6 l& i+ Q - res_buff.cur_buffer = next_read;/ [9 A. w8 p2 J4 \! \" _
- }
7 }2 A/ @7 p2 ^6 Z- `7 M - //清楚中断标识! h; H+ ]3 o9 ]7 W7 L0 j: Z0 m
- *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status
( ^4 p# e, I. K2 n - tasklet_schedule(&CHIPINT0_tasklet);//调度底半部
) k2 \( d+ x& r- G( w/ n } - * z( G$ n" P$ J! V, x X! {" {3 _
- 1 A6 n7 t: H" _! S; \ Q& H7 G
- return IRQ_HANDLED;
% |, c8 [& V0 j! E6 M7 k
! x- w9 `& w+ [" x- }' u# x7 d* Y8 z/ i. d' C+ W
- 5 r7 P. V' r# o% A& I
- //文件打开函数8 E3 m0 o) ?5 p4 H
- static int protocol_open(struct inode *inode, struct file *file)" x. x) W: U# o3 a7 b
- {
6 @. D" O3 L8 O+ Q% Z - int result = 0;/ ^9 r' X& M+ N6 ^. u* Z
- if(!atomic_dec_and_test(&dev_available))6 y! D% P, P7 q3 M
- {! l% }; {: j0 m7 y; m, ?( T6 {
- atomic_inc(&dev_available);
. Z% L2 M% {* k - return -EBUSY;//设备已经被打开
/ Y5 H2 J3 o/ K/ @* o - }) o0 G' s- p8 {# l# c
- printk (KERN_ALERT "\nprotrol driver open\n");4 n$ _. m" u# O$ R$ Q
- return 0;
, o0 b$ @. S0 P1 k( Q$ k - }6 h( @' d7 K, _2 m6 K% H
- 9 W6 ]* w1 J1 Z" n( k
- //文件释放函数9 {. B$ ]( J. a7 ?" \( [9 a
- static int protocol_release(struct inode *inode, struct file *filp)1 {; T: ~4 t& y1 m
- {
2 [# Y: E7 {6 y) Z1 u& s+ \0 x, b - atomic_inc(&dev_available);//释放设备,原子变量加14 h, x. |% f8 C6 D1 a: x6 d) `
- printk (KERN_ALERT "device released\n");. n/ z' p1 _0 A A+ D& D& H
- return 0;: q) N6 |" Y! W% c
- }
% W( t- c/ F T, j) Z - e. q* v5 d/ e6 g2 k- z
- //文件读函数
4 Z z0 W; }: _ - static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)
/ e! Y v0 W1 ` - {$ h7 P, T' \! y! U) D
- int ret = 0;
3 q; L7 H" l3 m+ E - //定义等待队列, L( l/ R' w$ V+ M
- DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列
, ^# t$ d B$ F; ?% C8 T, W - add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
: @2 a/ H! A+ j) G8 P" R - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
6 r' B" M7 j1 n. b' O$ K& V - {
) m+ b1 ?" Z1 ^- U8 p - //printk(KERN_ALERT"\nbuffer no data\n"); K( z7 f$ F7 t+ u/ @0 J; C% r# N
- //如果是非阻塞方式读取,则直接跳出# k5 b" `% B( {) N1 m/ `; J
- if(filp->f_flags & O_NONBLOCK): _+ K; {; x6 R) z7 J+ a
- {, c) d0 x$ [& a. K7 |6 R
- ret = -EAGAIN;
2 P& C) x+ s; k4 b L" u - goto out;
$ H7 V( I1 O% N5 p; e2 m" w+ Y& n - }
) C4 C; {% b! ~" e - //阻塞当前进程,放弃cpu资源
/ m8 G. @0 h N% q) R% l - read_quest = 1;! b/ x5 ]. b1 s
- __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠
# Q( k- ]6 C& p - schedule();//调度其他进程运行; k7 {" e/ m: C; Y/ {( j4 t3 M' K! i
- if(signal_pending(current))
+ o5 j- ~, d, _ - {
- p: `. {, D @ V2 u5 n - //如果是因为信号被唤醒,则返回到系统调用之前的地方
* ?1 J! W9 @) c: O - ret = -ERESTARTSYS;
# h: E/ @& I+ z) { - goto out;
4 v& j4 a* q6 V, n3 \' \0 ? - }
2 s g. C8 E. b# f0 n& l/ a - }5 v9 \' q7 D* ?% N
- //将数据拷贝到用户空间
* x. q# C! t; x$ H" V8 v% i# O - ret = k_linkQueue_getData(&queue, dst);( R$ B1 l" Y$ W1 y1 w. `, P2 w7 r
- if(ret == 0)+ @1 q1 B& t8 N( h. X8 K
- {
8 s6 X3 [& \! j& {2 p - //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
7 A( j0 U5 E' {- _2 q) V/ L - }
# C( B4 i" t8 v; k - out:" c" y3 i& v |! B4 x. t% I
- remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列: v2 b( |0 [7 ?6 Y
- set_current_state(TASK_RUNNING);//设置当前进程为运行状态
9 {" R2 h: K4 p) S9 U5 R - return ret;! @2 l, T9 B, F) _2 i+ l
- }5 N! }# b8 M( J# \4 Q; x" S
- 8 }# q; p! O) b" B) Y9 l4 m/ E L
- 0 J& u; V- I% }9 Y5 ^# u
- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)
$ X5 L; L7 |6 T& Y+ ] - {
% ?7 F) |/ m# ]: ~: N* X - return 0;7 J: b! g2 F0 x* ^# V% P8 ?" t
- }
; N0 I7 {% ~! l5 b0 r3 Y - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行% ?7 V( |# w4 ^* o
- open()、release()、ioctl()协同调用时被调用*/ Z. [; m2 ?: C9 a" l3 C9 u
- static const struct file_operations protocol_fops =$ S! e( e* q7 S
- {
1 p$ U6 V, O% {" a2 } q - .owner = THIS_MODULE,
% l! ^* ^5 w+ R* e' |$ Z" l8 ] - .open = protocol_open,
; o4 B' l" Q# I8 P( A U, @8 t - .release = protocol_release,9 r. Y$ F3 x) E* e- W" B @9 R, F- @
- .read = protocol_read,: e5 I0 B5 I$ O3 C
- // .write = protocol_write,. k, k3 r% m. B1 I# A/ p( w0 b
- .unlocked_ioctl=protocol_ioctl,) A) N% b4 H' S' u
- };
) V! O0 G" a7 }% y
/ Y9 a4 y; P4 f/ ~1 |+ x" i- /*设备驱动模块加载函数*/
( J0 L) {! |5 U - int __init protocol_init(void)) Y& e: v; a/ E1 r3 X1 X
- {
* h0 R2 d$ t- p) m" Y - int ret = 0;
" r) p* E% d5 o4 j$ l - int result = 0;' _. E$ c1 t2 I. F$ V% `
- //申请注册设备号(动态)
6 A; ]' Q7 D- r - ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); # Z+ ?, p6 O( s# J: U/ z$ E- v
- if(ret < 0)+ M2 o3 X' P- P
- {: V! g: p! ? B$ H, e
- printk(KERN_EMERG "alloc_chrdev_region failed\n");
& l& e1 o& A( z - return 0;& _4 d" K: Q# j4 o5 G
- }
Z$ K4 Z6 `: s( e - //分配cdev0 r; }0 E* d9 ~4 D; s2 M
- protocol_cdev = cdev_alloc();
9 f" P5 \" v- b4 `( {3 [ - if(protocol_cdev == NULL)1 W' O4 y+ R3 v7 R# l. W/ y c1 y
- {
! B1 A7 D* R" J, Z& J H! J - printk(KERN_EMERG "Cannot alloc cdev\n");: [9 V1 K0 C$ {6 A" ?
- return 0;
0 `! \$ d' T0 A' f( ~ z: x" n - }% i( f8 ~: |! d' ?" }
- //初始化cdev) i7 w6 c) o" ~5 P: V% E
- cdev_init(protocol_cdev,&protocol_fops);
0 r5 d, n" n d, A$ g4 q - protocol_cdev->owner=THIS_MODULE;4 J; Y3 R( b% u6 z
- //注册cdev
1 ]. O4 l. f) e1 m4 ` \( O5 t) ? - cdev_add(protocol_cdev, protocol_dev_no, 1); ' z/ ~+ u8 z P' ]
- //创建一个类
2 |$ M9 ]8 e9 ^: @( M/ O8 w9 v% k - protocol_class = class_create(THIS_MODULE, DEVICE_NAME);8 e" W$ F; J, w( k3 N) g8 D
- //创建设备节点! B2 ]" _% o1 `. T
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);
8 ~# @$ `: ^) H- Z7 d5 s - 9 @8 W3 L( i2 h0 h2 E4 t3 \
-
$ q8 R" e5 w0 Y1 @* i, p - //申请链式循环队列作为缓冲区DSP数据帧的缓冲区7 J! w- {5 u! i. Y
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区
+ L% V6 w; m- v/ s
# U) W) l6 d- i" c1 x) ], l- //映射ARM的核间通讯寄存器
, e# c% ]0 p( W) Y - R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);- s' F/ Y8 X; n6 {) ]9 b
- R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);
9 ?2 V3 U& Y6 p- F# m1 R4 }! X - //将物理地址映射到内核空间
1 Z) M4 q' h! ~5 V* p - mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);( r; S- J C' D
- //共享内存初始化$ h) S& v0 Q& ~, U/ i/ `
- SHM_ARM_Init((unsigned char *)mem_base);4 @3 T) n" g$ _) `' A; L- P, ~8 i/ D
- /*申请中断*/- o! A# M% p2 G' G
- 6 P8 r( {# ~) d
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);: O* J2 \$ H9 g8 s! N- P. \1 \
- if(result != 0)/ u( u) ^7 N! ^% Z: p( D3 k6 f4 D
- {( _7 f5 g/ M: a/ ~3 R4 D1 m" N
- if(result == -EINVAL)
+ D9 Y% X; _( |9 E* m - {
, J9 K* n+ C2 n2 X. W - printk(KERN_ALERT "irq request err:-EINVAL\n");2 I3 G/ F6 ?5 r7 M4 h. G
- }
' [) \2 `0 a1 N8 g - else if(result == -EBUSY)
: v/ O# W% T6 _ - {
' j& {, L9 n% _3 u3 U - printk(KERN_ALERT "irq request err:--EBUSY\n");
! T3 F( K/ ]& K W" W - }
5 Q* V' q0 Y# N - else
9 ]4 W& @+ b( M& y V# S - {
" M; l+ N/ I% r0 {0 e - printk(KERN_ALERT "irq request err: unknown\n");
3 y4 C, d8 c* F' T - }
; J: q2 U" i& w1 L) ^ - return result;
8 ~; u+ |- N: l' C1 L5 F9 p - }5 a+ X1 v4 Z4 Z, A$ h
- return 0;
$ ]$ A. i% H7 ^4 M - }
$ J9 R% b% ]. ~5 H# h" _- E V - ; V5 M5 Q6 \+ N8 E7 L( h
- /*设备驱动模块卸载函数*/5 J& j# m% n- D7 C
- void __exit protocol_exit(void)
# d, ]. @5 e* |/ E - {
; c5 q5 N+ w1 E' M - /*释放中断*/
, x8 U# b" e6 c3 t- ~ - free_irq(IRQ_DA8XX_CHIPINT0, NULL);, o: [2 L' \/ _9 X8 R
- //释放帧缓冲的内存. U; {# s* X7 `# N1 x( S c
- k_linkQueue_release(&queue);0 @2 P6 s+ v. ^8 c( a- S; J
- //释放寄存器映射# h J/ |" H0 Q. }
- iounmap(R_CHIPSIG);
. Q9 u1 ?* V" N. T3 _- m - iounmap(R_CHIPSIG_CLR);$ f4 G" C8 V+ c# [4 J( @0 O( c% p/ O5 s
- cdev_del(protocol_cdev); //删除cdev- o% K5 L! U' t* A; t( S5 Q
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号
2 {- _6 A/ B- g6 i, G - device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
% p5 W: e8 C. Q: Q" q1 L - class_destroy(protocol_class); //销毁设备类
$ d6 N( o/ ?1 x& z" Y( i' e - printk(KERN_ALERT "exit success\n");
* J% }( W- f* i& E$ F4 b - : z6 h0 H: ~9 R) P" Y7 r q
- }
! ^. A+ q3 ?4 r$ `: M: g* [ - //驱动其他部分省略
复制代码
! v. o! [, B5 B! g3 O
- x+ D3 t2 F, W7 E |