本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑
0 ~% x0 G% n0 r+ o6 L) [
/ x0 m. _3 o( R8 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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略
- {) ^4 y+ v6 m8 F& K; n - + P7 ~) ~0 m5 ^
- //引入其他模块函数和变量8 m" d$ L7 g9 ^7 o% f* o
- extern Ping_Pong_Buffer res_buff;( f( _1 b B( d5 `
- 5 G; ] x; E2 J
- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列
1 x8 n! ?; s; @0 P - extern void k_linkQueue_release(linkQueue *queue);//释放链队列4 B5 g3 J* W* u5 o3 V
- extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据
5 m7 V( g' N {& B4 c! Z - extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据5 x4 Z) z6 t1 U2 |% \5 h8 s. s
- & s: w+ Q6 R( v1 v/ r0 P3 i& `
- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化
0 B) p+ z4 G. H$ E2 [ - & M/ }5 h% Z& k% U5 O
- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1! m. o( K4 ]+ ?6 y9 M2 m! K. B$ Q
- //设置主从设备号
$ H7 C4 A. }2 I7 D* N - #define PROTOCOL_MAJOR 1
( H* P& |- m; M& i7 q+ ? x - #define PROTOCOL_MINOR 0
& z1 T" D1 P3 |$ r - 1 p$ a, n) ~0 {' e' V! H
- 7 l8 E2 e) O" S7 ]) R' c
- " h- |/ N0 k. H) [ o
- //定义设备驱动的名字或设备节点的名字$ ]9 X2 x( e7 P# \& K, J' ]
- #define DEVICE_NAME "protocol_driver"
4 G/ C! b% ^/ F/ f7 |
. J1 C; I! q& J+ ?6 X0 S
% d! K; N' j/ M- //定义全局的循环队列作为数据缓冲区# ~! O; z, d7 [. L7 _# T1 q7 C
- k_linkQueue queue;
& }' K9 g/ g. o0 |- N8 P+ o4 b
0 a& M) E, a, B. l' ^% A- //寄存器地址映射全局变量 `' j# a& A& m$ L! V) o- X/ Q! G; {
- unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器
9 R7 [$ `, P! W - unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器
* J% J, E3 V9 J+ h0 R0 L
, }8 G6 k$ M+ U& B: g, k- //物理内存映射全局变量
% k- g+ o& i2 R6 C) {. x7 C, ? Q - volatile void *mem_base = NULL;
$ E3 c/ _- o5 }* _ - volatile unsigned char *cur_buf_ptr = NULL;, V* z. }5 ~& j) a: n% n
- volatile unsigned char *data_ready_ptr = NULL;% ]% O6 t6 f- ]2 C8 b+ B
- 4 F8 n, [, D, h5 B) `1 x
/ Z/ L5 y4 P. u
1 ]( m, }( m# v+ P+ g/ C( x! T- //定义读数据等待队列头,IO阻塞! a" A0 R$ K0 J9 H O" D
- DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);
z8 j p! h0 H! c* B0 s* q
4 @/ y7 ?& x+ u) {7 `2 m4 u- //定义原子变量
/ |' n" P/ C( n, W+ w - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备5 [/ Q! q! \# x, ~4 Q
- ) H) P; I1 u1 r0 E( N- }0 n, _* p
- % m9 b* Z4 v' t8 r. I% X" J* m
- //定义设备类
. h( }! }' ]8 l9 G0 d. F! { - static struct class *protocol_class;8 N4 m/ i4 S/ L5 m. g' b
- struct cdev *protocol_cdev;9 M6 R5 i/ D, S7 [) i- I
- dev_t protocol_dev_no;
6 v; h; `0 c1 S A( h
/ z1 u& \. |& D9 o8 F- /*定义tasklet和声明底半部函数并关联*/( ?" j+ @" P/ z. X& E& \7 h
- void read_data_tasklet(unsigned long);$ m- [7 B3 F' G U w% L2 W3 @6 @
- " U! a/ j( r9 u/ W' \
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
9 z* f8 v+ x* H+ S6 X& S, K" z - //将CHIPINT0_tasklet与read_data绑定,传入参数01 c1 x h+ k# r7 @1 X
* G+ p6 D. M8 D* g1 B8 |; T- /*中断处理底半部, 拷贝内存*/
4 V0 v+ x0 @8 @% r0 G) C - void read_data(unsigned long a)! \/ s" m( d" \& S$ ]4 c* b7 n; z
- {
9 ~! E4 L4 I" o3 n+ f$ |: N/ J - if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1
- ~3 j; o% X9 O7 m7 d+ S4 T - {6 G5 E' H( P. ]7 M' j
- read_quest = 0;
' x4 f* o* }2 N1 ^% N! F2 C* F - wake_up_interruptible(&wait_queue_head);//唤醒读等待队列" X. @. Q- R2 Z
- }
$ F% v$ L$ d5 l, P - * j3 l& \8 p1 m/ i4 W
- }6 E0 f- M7 r4 V4 Q
- & ^( O% R0 m: p, q3 H
- /*中断处理顶半部*/) v b) }" P3 L4 `$ T3 M
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)* r. _4 d1 O1 y/ ]& n& |
- {
. ]* L0 f! _+ w$ T - //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
. Q8 _- k8 t# o) q1 Y - volatile Buffer_Type *next_read;' w" i* I0 P2 Y$ W) m/ n' k* a
- //如果DSP数据已经ready6 r) u( S+ f# {& _$ K# |3 G
- if(*(res_buff.cur_buffer->data_ready) == 1)
# d4 n+ S3 H# }+ c" i0 S. \ - {
4 Q# U8 ?2 E3 L* U9 X4 n, z - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer9 u) r# H8 _3 ^' o
- {8 V2 X0 u G* X) S0 \; C1 v
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer3 {$ R7 c H+ ~1 A1 A/ S b
- //printk(KERN_ALERT"read ping\n");5 }7 R* u# B3 U0 L! D: v. v8 g; B* E
- }
% U4 a8 H: W% ?# g6 J - else) I0 P* }3 u' i- ^/ P W, l
- {
; n& ~7 Z2 N5 A! C - next_read = &res_buff.ping_buffer;//下一次中断读ping buffer, i7 d6 i* p" G, c$ ]
- //printk(KERN_ALERT"read pong\n");. r1 M% p& y9 V v4 S+ J
- }$ _ T. Y9 i! z$ Q" @$ ]* N
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer/ s; g. T6 n! g. f) X
- //将数据插入链队列
: U0 A L% Y' a7 m( T5 h - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);9 d$ ^8 ?* @3 X) }% E
- //标识位都重置
1 x) s8 _6 ~! r' l4 X1 P1 r - *(res_buff.cur_buffer->data_ready) = 0;6 s$ R/ q5 Q* O
- *(res_buff.cur_buffer->data_size) = 0;
O' |7 r+ B" @5 @3 x$ u0 ] - res_buff.cur_buffer = next_read;
5 _* j/ W7 Q" {+ `! I3 B - }# E5 m; `0 a+ X1 X, K) O
- //清楚中断标识
% P4 ]* Z- p2 }! _% v9 a - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status
/ |& r% m/ e! d; o3 v* V - tasklet_schedule(&CHIPINT0_tasklet);//调度底半部
2 B1 s" j/ Z& a# S4 X% g1 ~
$ e' M" l( s [! C6 F$ X2 [( J+ p, b
# z) ~, F$ |- Q- b% u+ f/ `- return IRQ_HANDLED;
2 t7 x q1 J1 v( n! A6 o5 l8 s) G - : r+ d0 X, [: {9 q& h1 Q: ]
- }
- J+ @* t& K) t! O+ f8 v+ ?
$ a0 |$ {+ D8 |) [) O4 T$ n- //文件打开函数 N9 S O: W' K G0 T! e
- static int protocol_open(struct inode *inode, struct file *file)
& b# {: G9 C# S1 j - {9 G' e9 j1 }$ |) `
- int result = 0;+ V( Y4 e7 ]' ]8 j
- if(!atomic_dec_and_test(&dev_available))' y' w) L& D$ A" |
- {- P4 r- f+ t* F! ]
- atomic_inc(&dev_available);3 I u; f: K0 ]! D9 R8 B
- return -EBUSY;//设备已经被打开3 _- p5 x9 ]! t4 ?
- }& M0 P" w/ f. R1 d/ l3 y
- printk (KERN_ALERT "\nprotrol driver open\n");
4 J: n* h' }3 s! e7 O5 E2 d% ]. ~ - return 0;6 ?8 u/ Y( P% q- l8 m; \
- }
% V% [$ C* m& L/ D4 C$ T - ! W( [" \% z# Z" t6 G
- //文件释放函数
) z" C& h. t, a - static int protocol_release(struct inode *inode, struct file *filp)6 i: I1 n& l: c4 t L/ \
- {
# {/ x( C9 Y5 G - atomic_inc(&dev_available);//释放设备,原子变量加1" x4 M) O+ P/ j* ?$ t
- printk (KERN_ALERT "device released\n");
9 z* s% n, U! l \ - return 0;
; @( @4 Z1 @9 O; Z - } Q) p' A; m4 ~, r
- " n% K7 \4 R% x) K; m. h
- //文件读函数9 B- J2 S5 S& M8 E- \9 _
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)& W; ?" h& O+ K' c/ ~# Z
- {: t8 v! v. O6 t1 O V+ ^3 r( W
- int ret = 0;5 ?6 r& X3 B! @/ d! a- E
- //定义等待队列
4 U, [2 y& r& F. A - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列* t1 ~- ~/ L/ T! S/ Z0 j6 r% R
- add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
2 {. o! L7 r# s9 w. [ h. t - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据" G/ }! C: ^" x, C) N+ g
- {
0 ]# }3 p' ^- N! W) [( }0 J; z - //printk(KERN_ALERT"\nbuffer no data\n");
: m, S0 ~6 m6 n% _ - //如果是非阻塞方式读取,则直接跳出" N; I$ `. O8 h
- if(filp->f_flags & O_NONBLOCK)" @+ I- ^7 N2 W7 ~5 ` [
- {+ V# {- J2 D' l5 _ w
- ret = -EAGAIN;
% g: |7 r9 K' p; H0 @+ Z - goto out;
0 H4 ]% B' L/ h D7 x - }% l+ n( Z$ h! H9 `! ]
- //阻塞当前进程,放弃cpu资源
1 K; Y6 J( [0 J2 B% a/ I2 M4 v - read_quest = 1;
6 G# t8 p2 j! I6 _ - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠5 D, _' @( W+ N1 d: g; f
- schedule();//调度其他进程运行4 M1 N' v$ E% H: v1 n. |8 {$ V* Y9 U
- if(signal_pending(current))
; K1 |% X) F1 h7 c+ N. V* [( \ - {
$ i1 W- H( K( d! m, J* @7 t - //如果是因为信号被唤醒,则返回到系统调用之前的地方
; A- w; m( [% P - ret = -ERESTARTSYS;% P8 r2 X+ Q1 u! S/ K
- goto out;
6 z5 l9 I0 l; j6 C6 H! N - }8 }2 q/ ]: d! F+ A% W8 b& `
- }
) ]/ ?$ s7 l) v, A - //将数据拷贝到用户空间 F" F. B1 Z+ S) p7 j
- ret = k_linkQueue_getData(&queue, dst);
4 {! R' ]8 l$ \0 c# b' ? - if(ret == 0)* F& e W4 R; H3 J/ l
- {
4 h9 p1 @" `5 ]. g2 Z - //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
' v) e0 y( t" x" u* I7 d - }" Q( K8 Y* s. [. X. O/ W
- out:2 M: n3 p. M# V7 }; s: K% Y
- remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列
, H( ?: k, g% h- r - set_current_state(TASK_RUNNING);//设置当前进程为运行状态9 \( }5 C- C4 p! K
- return ret;! z" B' I$ |3 w
- }2 G5 z l+ {4 S' \/ b
' o7 o _) G, W5 k7 n: {+ w
2 R9 X% P6 w9 i; W: `- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)
9 T$ e, n+ Z8 t# {7 O$ j - {
, I/ y( |( l$ z `0 h- g" R( G, H' T - return 0;/ V x% W' P) z" f2 f. s5 q; y
- }
6 L$ O& f' w( d6 b, J& o - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行" {! s0 H3 v1 V$ U) j$ i
- open()、release()、ioctl()协同调用时被调用*/4 H/ c* J6 Y; ~. [- E" Z" O' `
- static const struct file_operations protocol_fops =
6 i# x4 ?% I, q$ D" c6 K - {
$ n2 n0 j, U5 G! [& U: w* A/ j - .owner = THIS_MODULE,! H' {0 @" ]8 _( A1 c, U
- .open = protocol_open,4 G! V: j5 t% \, n
- .release = protocol_release,
( W$ l4 \0 s6 u, P/ P3 d# p - .read = protocol_read,
3 g4 S3 D7 s9 e' S! q7 C4 n - // .write = protocol_write,
( K, M( d: ~5 }2 ^! L, q: ]* h - .unlocked_ioctl=protocol_ioctl,9 R- C( Z t2 U/ s
- };
8 j. Q0 }2 X* w' T8 \& d
. N/ R3 a9 Z- C+ Q( }) v- /*设备驱动模块加载函数*/3 q, T. P7 i, i6 @8 ^+ o% V1 q. O# Y. v
- int __init protocol_init(void)
( i/ W* f' d# N6 H - {$ b3 a$ ~4 J$ l( |
- int ret = 0;% h2 V' J: k4 Q/ R4 W) y
- int result = 0;
$ F9 d* u- G! J, y! B+ Z% O l A - //申请注册设备号(动态). ]# J& d, g9 G/ s+ [- ?+ V% S, ~/ A
- ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); ! P3 {8 I% {% x' [! Q/ |% Q
- if(ret < 0)
+ Z3 F- E. w( t- [! M( `9 @: \+ y - {
0 ]* \, J6 Z. ] - printk(KERN_EMERG "alloc_chrdev_region failed\n");9 ]/ z6 ?" S9 t! {' E3 ?
- return 0;
# q- ]3 L! \+ Q - }
; j4 A& o, M9 G+ q8 ] - //分配cdev$ {# ^2 w0 Q+ V( t( a3 _7 e' E
- protocol_cdev = cdev_alloc();. q' I: S: \$ M+ S* X* x8 w5 `# r
- if(protocol_cdev == NULL)
1 Y0 ` c S9 ^6 p- L! @ - {
D! x9 Y f* I. n3 ~7 Q - printk(KERN_EMERG "Cannot alloc cdev\n");& V( D) l1 K) R1 F3 P
- return 0;
! F5 W; H* r- D- | - }+ s) I) }$ m" ]; {$ j1 [
- //初始化cdev
* W! D! f- Y1 U - cdev_init(protocol_cdev,&protocol_fops);
l: x9 w) K$ e$ C3 O- Q* Q0 p - protocol_cdev->owner=THIS_MODULE;
6 }6 O q4 n& q$ Z7 F - //注册cdev: h) { O" C. I( @( e
- cdev_add(protocol_cdev, protocol_dev_no, 1); " q3 r# x& l4 k. t4 d
- //创建一个类! o' ]4 ?6 A8 H- n( p
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);! W, ^) [& H5 d
- //创建设备节点3 `3 R) {# |, ^( `6 ~7 N: V6 {
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);: a( Z5 B0 z, M; q
-
2 j- k3 T. l. h( ^ r -
+ L% e4 L6 r3 W, e+ J8 t6 t$ h$ V& ? - //申请链式循环队列作为缓冲区DSP数据帧的缓冲区
0 J5 G' w) l2 R c - k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区8 s3 I' x2 e1 o! x& G) g
- ! d) M' V8 w! Z! P7 X" j% v6 i0 \
- //映射ARM的核间通讯寄存器" g) ~0 c3 w3 ~7 f) W7 u3 ?
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);+ N+ t5 m7 W1 B4 X- Z, N+ `" r
- R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);
' Y! V) j! g2 j1 | - //将物理地址映射到内核空间
! n% j2 ^3 Q% w# o - mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);& i' h/ z! Z) K* K' ^
- //共享内存初始化0 s7 v- s8 C$ y$ e7 {, W1 |
- SHM_ARM_Init((unsigned char *)mem_base);
, P) }4 v" z- p1 C# z2 I - /*申请中断*/1 d- E S+ z0 q
- r' X8 B& u; Y% n4 I ]4 f- h- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);
7 t* _$ l) @5 M {$ t7 l" I. N - if(result != 0); t4 D) J( i; U$ ~" B6 N
- {
- R3 @5 r' F' P s- [ - if(result == -EINVAL)# g+ \' Z h3 \' q
- {
. H5 m2 }0 t; J9 f D- f# x. j - printk(KERN_ALERT "irq request err:-EINVAL\n");. s+ @6 b7 m/ [2 v) K! [) ^) o$ T
- }' C( ~$ y" M5 k3 @5 [+ g* h
- else if(result == -EBUSY)
' `9 \9 w* ?2 |/ X- D( S- f1 j# x - {
, o& N8 X) E! L* ]9 \7 j; | - printk(KERN_ALERT "irq request err:--EBUSY\n");
8 N% G8 o! S. s - }
8 y: J& q, W% S - else
( S+ W% p" w* p& S1 B- k - {, `" ?+ A0 R( D* v
- printk(KERN_ALERT "irq request err: unknown\n");
/ r7 C5 H/ ]* C/ S* f# B - }
: S: {' T6 \' a a: V4 _ - return result;3 |- F) `9 y; U. z( `
- }4 ?' V, u( g/ `% c; ~) ?
- return 0;' E( C- g% P" o8 m
- }7 n1 N; e5 k4 F, `) w- I2 Q
- , j8 B0 s7 [0 ]
- /*设备驱动模块卸载函数*/
6 ?2 B4 x1 ~0 D4 }' ~- A - void __exit protocol_exit(void)
* q# I$ Z. ~0 N. D# S7 V' d - {+ Q, X, U1 \& ?2 _; V' g4 ]
- /*释放中断*/5 B, s9 @. }3 P! o1 o% h2 b
- free_irq(IRQ_DA8XX_CHIPINT0, NULL);$ J8 u2 F% O9 o/ @0 w! q/ _
- //释放帧缓冲的内存& P1 w! {+ |% |- W2 i
- k_linkQueue_release(&queue);
: I4 ~6 A1 V1 l# x9 ? - //释放寄存器映射
$ H* o* u& a9 v! _0 a1 @ - iounmap(R_CHIPSIG);
- O Q7 f M" d v+ [* \ - iounmap(R_CHIPSIG_CLR);
0 ]5 }4 b: E6 Y - cdev_del(protocol_cdev); //删除cdev
6 L/ B. o; Q- x( L+ C+ h; w; i7 V - unregister_chrdev_region(protocol_dev_no, 1); //注销设备号1 Y8 r* X4 o) i/ w% L x5 b% J+ |
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点1 k+ N" w3 C) h: o
- class_destroy(protocol_class); //销毁设备类
4 J/ Y) D" z* x# g" {+ d0 x - printk(KERN_ALERT "exit success\n");8 S) u0 m. u: k4 u
- 3 ~( R. \ p% x( f; D
- }
, z% T# [' ~2 u G( B8 I- ?( m - //驱动其他部分省略
复制代码
& I3 g: ]/ C5 L q
0 I& `* a/ h2 K |