本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑 $ q8 b' `( b# M$ X! @9 U
6 J- X" ~0 o7 Z8 d3 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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略
2 f4 Q8 I1 X I" D; I - F( r* ? j1 G& f% Q
- //引入其他模块函数和变量
, e/ x+ k/ b6 o `, L* ]4 y ]8 R" v, g - extern Ping_Pong_Buffer res_buff;6 s$ s' ] F8 u7 w+ Y& l {
- / u( y0 u* d# M* L
- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列; ~: l9 l2 i: u" P n* k! W
- extern void k_linkQueue_release(linkQueue *queue);//释放链队列
( M6 b: x4 P. y; ^) B/ E6 u - extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据
- Y, f( N, O3 C8 k - extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据
$ v; p2 C$ ^4 q1 u* [1 \2 p - , c E3 d6 i# F; {2 ~
- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化, o5 b6 d; Z7 ]0 P+ w# T
- ( T2 @1 G; a: O9 T0 c! T
- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1) Q: K5 J$ b b
- //设置主从设备号! m) D8 W p9 e
- #define PROTOCOL_MAJOR 1/ d( R; a1 l* h6 M/ Z, A# J" u/ a/ o, _
- #define PROTOCOL_MINOR 0
/ U$ P- t) |! y$ Y# l
# n4 e6 \' c" s# y- t, z S
' `2 C$ C9 v% [( p4 c9 c
$ N7 e& g) @4 K! j$ f2 f- //定义设备驱动的名字或设备节点的名字
( U( R! d" A) y2 X - #define DEVICE_NAME "protocol_driver"8 }: |3 [+ x% C3 _; J
( D* Y6 ?9 p5 _7 \) |4 a- a F" _, h- 1 e( W ^6 e- n6 @
- //定义全局的循环队列作为数据缓冲区" J$ {9 m+ f0 F6 s; k/ e
- k_linkQueue queue;
; C. e; q {& f; K( l5 V/ ~! h - # O$ R8 k: }8 e5 N. L
- //寄存器地址映射全局变量! S6 [% S. M( [) B2 L
- unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器
+ r/ L7 [. j3 O- s% V - unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器
/ O' ]7 f+ r$ A3 H3 O0 V - C( `9 t/ i9 N2 X4 c) g6 R
- //物理内存映射全局变量
% Z' E0 }7 I; [+ s9 {4 `( d$ @' ]$ j - volatile void *mem_base = NULL;* C$ @% ^6 e8 q z8 U* s3 J
- volatile unsigned char *cur_buf_ptr = NULL;
+ m' L. _& ^8 Y0 ?7 A - volatile unsigned char *data_ready_ptr = NULL;
( T, C8 s. T& S6 \% ^ - 6 g+ E4 H; G6 {* j
- 7 R; @6 ]. h- ~
, R, V$ k4 H6 [( r4 W) g: ^! Z- //定义读数据等待队列头,IO阻塞
% X# w! W" p) A: b - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);* T! K7 l+ c8 Y3 \! ^9 ?: A
7 v" `( ^9 Q& M+ s8 U- //定义原子变量
. \6 f7 {; E% s! p - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备
( H3 @* |( F7 n; X$ r
) c' @4 A* {# M; S. l% }% m9 y7 f- . F, i- G0 A2 p5 U' K* U
- //定义设备类5 p: F+ V- p8 H9 u$ R
- static struct class *protocol_class;
8 _, y/ P& f3 k5 e" N6 r! h. x - struct cdev *protocol_cdev;
$ z+ c* V- D. p6 U" ]/ k" Y - dev_t protocol_dev_no;
7 \; k, M* C0 B4 H5 n0 ?, ~
1 C% L/ M# q% _( h- /*定义tasklet和声明底半部函数并关联*/
# \; K, B; n9 O( {5 W3 O - void read_data_tasklet(unsigned long);
4 d4 B |& \; a - $ I% @* Y! |" `6 b, \
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);# p/ t6 a7 y9 x9 J4 g
- //将CHIPINT0_tasklet与read_data绑定,传入参数03 ]* v9 @9 J7 i$ C2 H
0 H4 D! M n# R- N& N! N$ d7 \) c- /*中断处理底半部, 拷贝内存*/
4 K- E" S. n: M - void read_data(unsigned long a)
+ H; |, E6 p* o- S# J - {
5 o- B& G* D# y i7 E - if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1
' C2 V2 \7 `& L - {
. S# S& c6 S9 b) W4 V# t3 ^2 i6 D - read_quest = 0;$ G8 p! N* `5 N! v/ Z8 H
- wake_up_interruptible(&wait_queue_head);//唤醒读等待队列* a' \1 z, C ?" @( j3 d
- }. e" B6 x5 W ?
) Y0 s7 m: [. W- }( J4 x5 ^' x% p `1 \
- 1 [* x& w9 K" W
- /*中断处理顶半部*/
8 r/ _! I5 l! B) a - irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)+ {6 t7 K- q9 x
- { S5 b t0 |, ]- P
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
# H; e) x2 b3 l - volatile Buffer_Type *next_read;
8 A. S9 z4 i' a - //如果DSP数据已经ready
& K. f; k5 _" D/ k9 \9 q B - if(*(res_buff.cur_buffer->data_ready) == 1)4 c, d% \+ M* Q9 {* g* k
- { h2 I- W8 n5 z( ~
- if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer' f9 p/ C1 T+ }9 Y9 c9 p, V
- {
/ q# i7 @ Z2 s* W - next_read = &res_buff.pong_buffer;//下一次中断读pong buffer
5 h! ~* U! v/ x6 u7 H1 U+ p; {- Z) k - //printk(KERN_ALERT"read ping\n");
! m$ S0 y8 M0 r- k X; D* e - }
# ]6 Y% Q5 o% R( @ - else' \! B' _; Z# ]# }7 z. c
- {
2 g1 X5 Z- L* e5 o" H0 @7 D1 ~* @$ A - next_read = &res_buff.ping_buffer;//下一次中断读ping buffer
, _" [: C' H+ y* e9 l, S - //printk(KERN_ALERT"read pong\n");4 v0 l- [4 R" ?& w7 U
- }0 [6 E1 e7 ~+ x& e
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer3 z- K! ^+ T0 h1 `" l B: d
- //将数据插入链队列1 |/ y, @' W$ \2 r6 t
- k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);
9 M; P5 H& D- X# v3 p4 x - //标识位都重置
) j# Y! I% G( g B* ?9 Z - *(res_buff.cur_buffer->data_ready) = 0;9 {& z) S+ d& k
- *(res_buff.cur_buffer->data_size) = 0;4 f1 c+ S: f2 z* l% v" \' Z, L
- res_buff.cur_buffer = next_read;
3 g9 ?* I# e1 r - }6 l& V6 C4 B+ J
- //清楚中断标识6 i; T: W( e, [: c1 l
- *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status
, }+ ]1 z% k+ l# v9 n - tasklet_schedule(&CHIPINT0_tasklet);//调度底半部 $ k% p" a3 w: r/ M, I7 `7 a
- 7 k' }+ J7 V7 m% P" Q! q5 f3 P5 A
i. S, a- {7 K6 R) G$ v* g/ T. L- return IRQ_HANDLED;
V" Z% H9 Y# s0 U) ^7 {6 k - - P& M6 b. i' Z/ u0 N
- }6 o8 D f; _2 F. @2 f, @" V$ \+ N7 n. z
% P& _$ `/ T) g- //文件打开函数
, x4 v/ f$ X8 t- H" w - static int protocol_open(struct inode *inode, struct file *file)
. X" V' l/ m; L& ^+ [ - {
6 E. ?! C" z! [8 ~: y# y) I5 t - int result = 0;& [6 h9 i. I4 Q2 M& |/ J) Z
- if(!atomic_dec_and_test(&dev_available))
7 } w* t: n( Y: }+ v3 P; T/ g - {( e1 u" M5 k! ^) V; m
- atomic_inc(&dev_available);
9 }* _5 b% S% i8 ~# Q - return -EBUSY;//设备已经被打开
, p+ Q8 U; X. N( f6 b6 U& F - }: r# O* @$ \* K, O5 d8 B; }+ B$ I/ K4 b
- printk (KERN_ALERT "\nprotrol driver open\n");
4 x, r- F3 a* a7 f: U6 u# P - return 0;
* r) X5 H: v O - }. D& d7 h3 z6 c2 l) b
( ]. L* h4 {6 l0 U- //文件释放函数3 ]+ T9 k: w- H5 G- T/ C
- static int protocol_release(struct inode *inode, struct file *filp)
* }0 V$ @ N' n" ~# U - {
, w" I% d) N8 R2 N) N) _ - atomic_inc(&dev_available);//释放设备,原子变量加1
0 `% g' z: X, V: V" L3 E - printk (KERN_ALERT "device released\n");
$ `) B, h. J) q% e5 V) k* N2 d, f* O - return 0;+ d/ U& W. y6 s7 I0 `# Y$ U
- }, H x, h5 R, W- M( h4 e
; N& Y% [: f' L' ~, b& ^. I- //文件读函数* y- H ?! K* X; M* b
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)
3 p5 D6 m! B. H o - {" E( q% n4 l# ^ m
- int ret = 0;
) a, ]' }/ D0 g8 Y+ [ - //定义等待队列
' J! A! ?2 O3 ^8 M - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列* ?7 A! r2 d5 L2 F
- add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列3 L! Q( Z0 R, N j+ {
- if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
7 ~! c; v1 j0 }6 Y/ k' W - {: I$ `. R5 X6 F# j
- //printk(KERN_ALERT"\nbuffer no data\n");
+ E# c; h( j. A& ^ - //如果是非阻塞方式读取,则直接跳出
+ l1 v9 }9 H, t7 n6 u: `) e - if(filp->f_flags & O_NONBLOCK)8 f8 I+ y! Q$ G: o! j6 |
- {" Y6 h8 Y) y& w* y
- ret = -EAGAIN;
( D7 }0 I1 O* `/ l6 i# r - goto out;5 W, d) r" R$ w* R' N$ |1 w I
- }5 P% s* c. E2 O8 O! P+ E
- //阻塞当前进程,放弃cpu资源$ I$ O4 k9 B- g; @' ^
- read_quest = 1;
4 m3 ^7 ?5 B; ^* u T. v - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠 z9 a. N7 }6 f7 u
- schedule();//调度其他进程运行4 j# R3 {( u" \2 t. o; ? }
- if(signal_pending(current))* Y8 i& j* d7 o3 ~: s: K
- {
. ]# _9 F$ R9 h+ n$ ~ - //如果是因为信号被唤醒,则返回到系统调用之前的地方0 J) B. A/ m$ h& r7 y9 o
- ret = -ERESTARTSYS;2 T0 ?8 x% b* o( u; W
- goto out;
$ a; s9 }* O2 w2 z& v - }
~% _3 }( R, c2 y - }
C# S- k- }& q) ] - //将数据拷贝到用户空间9 O1 @( ^+ A* W+ g
- ret = k_linkQueue_getData(&queue, dst);* J. I) P% }1 |' _9 r4 [; Z# E
- if(ret == 0)1 Y: ]4 N0 ?) f7 Q! N
- {
/ J, ~ ~% I9 a+ P/ S% k9 ~0 b - //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
1 c+ z" q2 X$ |* y1 |. ~ - }- w3 l& ?/ b$ o8 P! `; ^$ Y
- out:
9 I% f; D# P9 _ o, w* \* @8 y - remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列. I1 P% O/ U3 \* q+ [5 Z9 w6 D
- set_current_state(TASK_RUNNING);//设置当前进程为运行状态
. O+ W/ S/ c2 d! \* A - return ret;
+ u* @! Z6 z9 ~$ P0 r* `& i4 b - }. B+ d7 u& i$ A9 e0 B( o
) b) k6 D! @0 x" l6 s
9 M" H6 Z2 b- r- A+ z. E6 G- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)
" @/ ~1 b$ G: Q( F9 f" x2 r+ T; K - {1 M8 @. z: S$ U4 R7 f
- return 0;
* @, Q5 W4 o2 J - }, W1 T6 e% J1 e# V
- /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行3 F1 ^3 l( T' T- X- V$ H
- open()、release()、ioctl()协同调用时被调用*/+ V/ D: l) Q( m9 T
- static const struct file_operations protocol_fops =9 v$ m6 D2 z0 A2 Z/ c7 _' S/ e4 [
- {7 X' l1 ^: n2 v- H; f% A! a9 F
- .owner = THIS_MODULE,
. Q1 f% |7 N% n* b) _0 Q2 r - .open = protocol_open,* R2 @2 G0 ?+ T9 _: Z: d. i
- .release = protocol_release,( U, c' {! U& b
- .read = protocol_read,; N7 V' ]9 M" B
- // .write = protocol_write,
4 m$ \. `) R; E! U - .unlocked_ioctl=protocol_ioctl,7 c6 }% _' L9 l2 p
- };
0 W% F9 k T9 r! [0 R6 K
0 u2 t! M# H5 T, ]+ v1 z- /*设备驱动模块加载函数*/
) Z6 d- d& _3 I u1 P - int __init protocol_init(void)
& x! |" y! x3 ?9 N4 S# c, F - {
, b P B& g# M/ w7 I - int ret = 0;
, v- |' f! c, o6 [- f - int result = 0;6 i; n5 g J3 P1 c7 N/ ?
- //申请注册设备号(动态)4 t2 J, Z2 L8 H9 M/ N; c# u
- ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME);
: c/ o, G0 }. y - if(ret < 0)
" u, L* o9 [! j5 ]$ u+ d - {
. r9 ]0 a5 P9 Q$ j4 [' V4 x - printk(KERN_EMERG "alloc_chrdev_region failed\n");5 L' M2 x( h: ^4 R: z# ?8 L
- return 0;
% `, c% J" A* S! ^ - }
. L3 ]0 X* z2 C& d& T; u5 S6 c - //分配cdev9 A# k* b7 x9 V+ D5 B
- protocol_cdev = cdev_alloc();
1 ~) \9 F2 ~! k) H8 C- s9 U - if(protocol_cdev == NULL)
. C7 L* E- Q. k! `1 t( M3 z - {
; \# E2 J6 n! d" g- m - printk(KERN_EMERG "Cannot alloc cdev\n");, {; }' z$ B! {3 Z" @6 A& ^* \
- return 0;# q0 g5 ~+ C& ~- M) q! Q
- }% ]1 X6 x% P* d8 g) p0 u; Q" e
- //初始化cdev
2 k6 X! T+ {! }5 X! O* e - cdev_init(protocol_cdev,&protocol_fops);; \/ ~5 Y6 S# R5 X+ E% T
- protocol_cdev->owner=THIS_MODULE;
, {/ N5 X* @* ?+ N9 C+ o - //注册cdev
. E6 d4 A7 A' Z6 l* C$ T0 ~0 } - cdev_add(protocol_cdev, protocol_dev_no, 1);
) R3 x; n: z; _: d - //创建一个类7 ^( ]% y1 D2 u% U
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);' g9 V" ?1 ?1 ?5 T. c5 i
- //创建设备节点# ]7 I+ K1 M: w& l- z' O
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);3 `* W4 M7 l( \: O* x4 n
-
6 F$ o4 X! i0 d - 9 K9 M% s& E& W5 ^6 s2 |! O* ]$ P) Y
- //申请链式循环队列作为缓冲区DSP数据帧的缓冲区
! ]) t. P5 b7 a8 m - k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区- ^6 S! c; h' {- L# C6 P9 x+ R
- , n) B* t+ o2 ?
- //映射ARM的核间通讯寄存器9 U3 k% p7 c7 G- h" }3 P8 ]
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
7 C8 v' \7 X* V* H - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);3 b2 }8 N$ s( u6 I% P' k- d% ?
- //将物理地址映射到内核空间4 N1 U3 T' e; E* n
- mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);2 I; U% A! @( b/ `
- //共享内存初始化9 ?1 d4 L: x4 U( @* R5 \
- SHM_ARM_Init((unsigned char *)mem_base);. ~) i1 p$ O0 z/ B9 T
- /*申请中断*/
5 x9 q f, q$ H" \- z - 1 H. n$ j. ~8 Q: M- @9 \
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);
8 m4 {7 y1 k5 D( u) p8 ]. f - if(result != 0): Z# q* _- M4 t. R, ~
- {; T# f- y1 J2 i; M
- if(result == -EINVAL)$ s* p8 j# r$ _ j
- {: R+ X3 p2 j, X+ |# n2 s8 R
- printk(KERN_ALERT "irq request err:-EINVAL\n");
( D) O8 v4 h# n% ~. e/ A: @3 { - }
5 V: t" k8 K6 D9 Y! P: F - else if(result == -EBUSY)0 ^! C5 N% e9 a5 I6 e
- {2 O Q/ A' c0 g6 v9 f9 M
- printk(KERN_ALERT "irq request err:--EBUSY\n");6 n/ R3 i' A/ O& h4 F( ~3 D
- }
4 D1 q6 c2 k: |1 Y( J/ ~* W1 S - else' S- _; C& U2 }: m% Y" g
- {
3 N$ B: G* L7 ^3 a4 t9 v - printk(KERN_ALERT "irq request err: unknown\n");
; X4 z1 L3 `" d" ? - }
: @$ w/ m, U& x% P6 g - return result;
4 T6 q4 ]; n6 i0 m4 I9 }& c! a4 D - }
# |% T3 |5 _ h/ Z$ W - return 0;& i1 ]" e, G' Z- r4 H0 j
- }
% c1 V( ?% p$ L7 H& C2 S7 Q4 Z% N) ^4 T - . _/ _$ |* e( ]# L
- /*设备驱动模块卸载函数*/1 z0 y0 N! S9 H4 u9 }% |% B
- void __exit protocol_exit(void). P- B% s$ q% B7 @3 D" s
- {" l9 ?: E6 Y/ `, c; E
- /*释放中断*/
' T; a: j0 P' ^8 D' n - free_irq(IRQ_DA8XX_CHIPINT0, NULL);
/ Y1 o9 s* _/ P3 _- n: H' @ ~ - //释放帧缓冲的内存9 Z# T& _8 K4 T. p+ M. c4 ]
- k_linkQueue_release(&queue);
! s; F2 \+ u/ q) e% |& j! h - //释放寄存器映射* k* D# Z- A* ^& t2 z; v
- iounmap(R_CHIPSIG);
* R0 S/ Z: p+ Y! @ - iounmap(R_CHIPSIG_CLR);
$ g) G9 h& }1 h8 d - cdev_del(protocol_cdev); //删除cdev
7 U- R) x9 M: B' p2 l, E3 u4 T" S - unregister_chrdev_region(protocol_dev_no, 1); //注销设备号# {, B' }7 l) Q8 I( L3 l
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
; _9 e6 `( V K! b6 q9 {3 ? - class_destroy(protocol_class); //销毁设备类1 ^& o; }2 s3 N% s+ _5 q! A
- printk(KERN_ALERT "exit success\n");3 b/ ~5 m& s7 H+ }7 F! V
- - s7 u; f2 q4 h! U: B
- }
- H' N! A- D( Z. x1 Y - //驱动其他部分省略
复制代码
' r" e+ a- B: U3 f
: ]1 P; T; h% c |