本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑
+ I1 w. H+ j9 j) F" Y7 p4 y
' S- y) M, E7 c s( h项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略
, _8 V$ ^; I" c% ~ - ! j/ M9 e# C7 p6 L: b
- //引入其他模块函数和变量
% g" G# Z* ~$ @( W" Z - extern Ping_Pong_Buffer res_buff;
{# s2 p: Q4 F' ^- { - V% T0 }' w2 s$ A/ O7 l4 U0 C
- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列
% f7 ?* @ z8 R7 S - extern void k_linkQueue_release(linkQueue *queue);//释放链队列
' j( r6 q/ M- k# {8 S - extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据
* P7 Q' s4 w8 z$ G - extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据3 [5 D" |6 C/ p3 @7 F7 L
- 9 b5 Y0 x8 Q# l! P4 @
- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化( u Z, L& i2 }3 \" k
- % Q, \, L+ s `. L) X1 d
- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1$ D. ^ h' @' L* i( W
- //设置主从设备号7 K: C! Q, I, c! S6 g g1 F8 C, ?0 x- f
- #define PROTOCOL_MAJOR 1; ]' r9 M6 c7 h9 [9 I
- #define PROTOCOL_MINOR 0
6 c& T0 ?3 s' E/ m* r2 J! A7 o
* c) l. O& b* q8 d- ) z8 E, ]6 k+ ~, y' C
2 v }9 B. Q/ @6 V) {+ w0 ?- //定义设备驱动的名字或设备节点的名字' c8 d* L- @ F- h% @+ P" m5 q
- #define DEVICE_NAME "protocol_driver"
9 d% h* B! M$ F) e1 m - 1 p! d, Y) b3 m: T5 C
; T# D7 m, g$ f& x8 i2 u' f- //定义全局的循环队列作为数据缓冲区
" y0 T4 F' o+ u' Z8 V$ _ - k_linkQueue queue;* _% \+ {5 B" V- W8 _: E
- v2 G( B4 e' s
- //寄存器地址映射全局变量
, z0 o* h3 i. G4 p - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器
+ n( y$ n& i4 K1 d- ` - unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器
$ t( O/ [, ?9 s8 ?& S! u
6 @: p! P5 W2 R' g0 H4 `- //物理内存映射全局变量
% R: z& F8 e+ E* D3 n+ Y: u - volatile void *mem_base = NULL;# Z) m+ T. b- q+ |
- volatile unsigned char *cur_buf_ptr = NULL;+ g& o. R) W& A% v
- volatile unsigned char *data_ready_ptr = NULL;
5 K; k3 y) }- K* {6 F7 v# ?( ^ - 9 y3 k) h: G% L# r
% z, T9 ~' {; y8 e
1 @0 B7 P0 F7 |6 K5 ]- //定义读数据等待队列头,IO阻塞
3 i6 E0 Z [: p$ @/ M6 ^& g - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);
# s+ B* E) e) J8 K% L- U
/ G2 P! [$ @/ B( H) e- //定义原子变量0 c ^' c5 x6 A0 X2 @
- static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备' H6 k# Y! `) \4 X* e* e
- q( {% Q) ]$ U- }
- # p% w( C9 w# R) C0 H
- //定义设备类
j- e" y- _5 t; s+ x+ H7 y0 Z - static struct class *protocol_class;
4 I! D5 \9 t& {; t - struct cdev *protocol_cdev;2 i. I& b& M4 a, m
- dev_t protocol_dev_no;
$ ~0 M. j9 {' U1 d! V
( f% L: f! w' N; H+ E. n- /*定义tasklet和声明底半部函数并关联*/+ t+ V$ v# l3 ?& I$ G
- void read_data_tasklet(unsigned long);: H5 w+ x3 [3 F
- ; x! c; D6 c) |
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
1 I0 T# k8 Y0 i% T9 s( B - //将CHIPINT0_tasklet与read_data绑定,传入参数0
9 r F5 R' D8 F2 a - ) g. k4 e8 { g3 G% b7 |! q
- /*中断处理底半部, 拷贝内存*/
8 O) S9 Z' Y2 ]1 X2 A. v - void read_data(unsigned long a); u C% S9 I* O' K9 b
- {
, ^ Z& T, H& c0 @ - if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1" d/ c" g% z6 j) Q. ]: {
- {3 C; X+ u$ t9 r
- read_quest = 0;2 I, s8 ~+ p) B Z9 C
- wake_up_interruptible(&wait_queue_head);//唤醒读等待队列/ {/ |. S. z6 b* \, S: Z
- }
0 ^ i* t* Y4 r; @ Y. g5 R7 b
1 {! i3 K: f. h+ h0 D1 x- }
3 V. S9 d+ n& V, \+ ?
# g2 }' ^/ j" @% t+ V- /*中断处理顶半部*/
% }; C4 O( |' E2 Y7 A - irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)
" L* x% p% W5 H6 a1 P- Q V# H - {
) }! z2 Z2 d2 N+ D7 j - //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样" w3 c% m# ^, ]/ A/ w
- volatile Buffer_Type *next_read;
" Z ^: Z4 a& p) v I7 ? - //如果DSP数据已经ready
5 F; j! k' Q5 R8 W/ c- o% R0 U4 E - if(*(res_buff.cur_buffer->data_ready) == 1)! X( ?) ^" P' e
- {
5 j9 X% f9 P7 y- Q - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer& k$ T2 m/ C# _' c
- {
F4 e3 i) b. e, l" p4 p( _- Q1 ~ - next_read = &res_buff.pong_buffer;//下一次中断读pong buffer
7 ?2 F/ X: E- x3 X e - //printk(KERN_ALERT"read ping\n");
# X( U- C1 i! j y - }' z: d* P. U) m
- else
+ e3 Q5 x7 P# @" E - {
& Y6 j( P. Y+ Z! C4 U# T7 K - next_read = &res_buff.ping_buffer;//下一次中断读ping buffer
! {$ a3 O4 ~0 m9 x - //printk(KERN_ALERT"read pong\n");. v7 W! P" O8 m( J
- }1 [5 p1 ?8 _1 Y/ Y' |
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer
; @5 c' q7 D1 e. b3 P* T - //将数据插入链队列
2 @+ R+ [5 J0 H$ a4 V* D - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);
2 D3 d! \. M& S3 I - //标识位都重置
1 }8 T8 P/ a! O- x1 P5 I) T - *(res_buff.cur_buffer->data_ready) = 0;- m: u( u/ y& }+ ]2 F+ G" z
- *(res_buff.cur_buffer->data_size) = 0;+ G" x6 S4 f$ S9 t, |# y
- res_buff.cur_buffer = next_read;" d; ?' a* \4 d3 w/ i
- }2 R) _2 K- F6 {7 p; a4 T0 p
- //清楚中断标识
. Z: T# W9 I( i5 E$ n. E- t - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status# o5 H( C& l- F$ m# f: x1 Q* r- J4 ~
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部 1 Z* l6 r! Z" R S5 P
- 2 B$ H: S- P& k' W0 J
) v* _7 y9 r5 o( V! r" Y$ X* `9 k- return IRQ_HANDLED;! G" ]7 p' X Y+ g0 c0 }$ \
+ p- \" T l+ v- }1 L& o4 G" G/ s4 o- a% `" v4 q
- & z* R ]8 t* P( `( P* U
- //文件打开函数3 \1 P( ? b: N+ \/ L5 M1 R' t y
- static int protocol_open(struct inode *inode, struct file *file)7 @" d# z# P, o' Z# b
- { N, B, n" a( p' ^. [3 `& Q
- int result = 0;1 \/ u9 G6 S T4 q4 T7 N: I- i
- if(!atomic_dec_and_test(&dev_available))
# m% r9 |5 e" ^& m - {
- X! S3 O3 U/ s# U0 _ - atomic_inc(&dev_available);
, t: d8 D' Y3 W& L* h* h/ @; S# i - return -EBUSY;//设备已经被打开" I" Y1 ~. n2 ]7 I% U/ e2 v2 w* v# c+ `
- }/ Z5 l1 _# G! D! d: m9 y5 a5 Q
- printk (KERN_ALERT "\nprotrol driver open\n");
; l) Y4 v H0 J( V( {- c - return 0;4 O, x% l/ R5 f. k# i* }& J
- }
, h! Z2 c% A$ @" ?- I% y7 q - 0 o% z2 q6 Z+ a1 m: Z: O. Q/ U6 |/ R
- //文件释放函数) g- f0 r' v# m) J
- static int protocol_release(struct inode *inode, struct file *filp)
1 F, R3 t4 z) k% X6 ] - {/ ~7 a) R$ Y$ T
- atomic_inc(&dev_available);//释放设备,原子变量加1
4 |% S: _9 v. C K3 i/ Q! J1 W - printk (KERN_ALERT "device released\n");$ ^, F/ V; ^) i9 i5 e
- return 0;( \: E! k8 k. {# R2 C# i9 Y
- }
6 _% Q! ?) q4 Z, W- u3 x
6 Q7 j7 K d! L4 A' V1 W) L- //文件读函数7 ]/ ?: w# U. R' p ]
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)" ~- C$ v# l) W7 P; @' x* H0 n
- {0 q/ m, R; H$ b
- int ret = 0;
$ g1 E/ d& ~1 Q! m R - //定义等待队列
1 t. e+ u1 N' v6 M0 M5 q4 L - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列
3 P: k8 \$ x9 O - add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列* ~& @; }' a* _3 V1 F7 S' L
- if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
9 \* F+ ^0 a3 U- `3 g! A( a - {' C0 x3 e9 j7 q$ V
- //printk(KERN_ALERT"\nbuffer no data\n");; _0 U% v( b' _( j
- //如果是非阻塞方式读取,则直接跳出
2 m5 P2 e( D' {8 d - if(filp->f_flags & O_NONBLOCK)' x& {3 g2 M1 o- F+ C* j+ E B
- {
3 Q0 O0 O( {& Q; E - ret = -EAGAIN;
8 K; z1 C7 s6 i1 w4 m0 ?2 z) R - goto out;/ F; S9 o# u* |3 _0 Z" V
- }- H" I6 V, Q q8 J
- //阻塞当前进程,放弃cpu资源0 j2 K4 c2 J( ?5 b# M5 f, j; q
- read_quest = 1;
5 H7 e) H! i8 ? W3 P( B - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠
3 T; h4 q9 f+ h2 g2 J7 q - schedule();//调度其他进程运行) |& U5 j) a3 r" }: A4 P$ c
- if(signal_pending(current))
% |6 h+ A% ]' m1 x" u" S5 h - {
& g8 l+ t3 p. E8 Y( b! ^ - //如果是因为信号被唤醒,则返回到系统调用之前的地方
7 l1 j* Q3 O& H }7 ^9 R- D - ret = -ERESTARTSYS;7 X1 w, U5 |: W. N8 \
- goto out;
9 D- P; D! M$ }' m4 ~ - }! c- K* B% f1 O( z) j$ r
- }
5 V- O5 @% G) D- k# o3 r& }0 V - //将数据拷贝到用户空间
" s& J% r, H& `3 `1 F a3 I - ret = k_linkQueue_getData(&queue, dst);
% i9 H. H" z2 Y$ k7 f - if(ret == 0)$ \7 B/ o* a! |1 r2 R/ l
- {
. q9 U1 H9 W& x% P7 f - //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
; O6 z7 O( u- y" \: S - } d- w" }5 g6 O' D' x- s3 e
- out:
; \9 E) h' R1 N/ }8 T8 k( V - remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列* E1 A3 A* m8 q6 W8 U6 @7 n
- set_current_state(TASK_RUNNING);//设置当前进程为运行状态
/ D0 F& q6 Y1 ~! h* f- @4 O - return ret;; k& M: W; E' i* g5 X
- }
+ {* N/ e/ b, B; g1 O' l+ q
- i, g8 k# ?* ~/ ^* T
7 |% x$ } N2 j {, ~4 [- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)
7 C, u) @# i0 N6 F; f3 [! M) C/ } - {- x! F! a* M- C" W# [$ q" L
- return 0;
- @* V+ `; e, z; A5 C: M7 v - }
0 g# _( U1 f2 V# Z' y6 x - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行3 a( |; F: z c9 \/ n" D
- open()、release()、ioctl()协同调用时被调用*/% B" e6 a) R4 P
- static const struct file_operations protocol_fops =7 z9 t" b$ m3 x5 w7 ]
- {7 Y* J4 d! m$ ]' E, }
- .owner = THIS_MODULE,. Y, v! M; s' a
- .open = protocol_open,
! E7 b0 y) q, \! ~ - .release = protocol_release,
% i. }8 |. M, g V) I6 k - .read = protocol_read,( P% s& ?1 w" I" \: W3 ]
- // .write = protocol_write,
2 D# b/ L: ?2 B1 i4 I - .unlocked_ioctl=protocol_ioctl,
) \6 R! H. ^1 S* c9 N: s - };
2 k$ t6 O% p% O8 Z5 @2 B
! i- P# K8 e; C& U, p, h- /*设备驱动模块加载函数*/
7 ~: a, E- z6 F% O# A3 g - int __init protocol_init(void)
. ]1 L* z. S: D O& { - {$ j, M, v2 V& h' v4 n- u* B
- int ret = 0;
$ q6 z8 ]( H, `/ X* ~* N5 P+ A. I1 S - int result = 0;
) `3 e$ \5 Z' {2 t# f3 ^; x; d/ f - //申请注册设备号(动态)
: H' D( S. `# }* M1 A - ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME);
) [0 ^4 b3 C$ V" ?. H - if(ret < 0)
8 q$ C4 n( n9 t& {' _. e8 h - {
1 M, I: Y$ J5 v0 v' H# c9 F) T - printk(KERN_EMERG "alloc_chrdev_region failed\n");
6 T4 p4 K4 r: Q - return 0;
# o. B6 t$ A( g5 D+ F, { ~ - }- \6 w. t" k0 }* ^: l: U. I. w
- //分配cdev: I# p8 x2 y2 [' y- P- R' h z& c
- protocol_cdev = cdev_alloc();
. ?' `! W* ]7 ?, O4 Y) [ - if(protocol_cdev == NULL)
! a3 `+ _9 f' X& \9 t- x: [% L - {/ P% R6 I' A4 `
- printk(KERN_EMERG "Cannot alloc cdev\n");
" N: I" D: L; `: M6 y% F* J - return 0;1 v0 X( r }; N5 q
- }
7 D& `6 ~* ?' q+ n. M, O) O - //初始化cdev
" `# e* I' B+ z8 s; h) r) a9 D3 b - cdev_init(protocol_cdev,&protocol_fops);6 a. _. W. c( K' r3 ?
- protocol_cdev->owner=THIS_MODULE;
% Z3 e- F8 u6 j - //注册cdev
5 i- p9 |. q% i6 u: r% h - cdev_add(protocol_cdev, protocol_dev_no, 1);
7 J3 q% `) m3 @) [& v2 S! u) ? - //创建一个类9 Q( `5 n/ m( J. G+ V) [
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);
7 k3 R. B% Z+ o - //创建设备节点2 T1 k* ~, V5 B6 K' g
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);
: P; G1 t4 @5 a' J3 T) Q6 I -
" R5 A2 g& m5 h- n! l -
8 a; M& b5 `0 {. }0 Y - //申请链式循环队列作为缓冲区DSP数据帧的缓冲区
4 v, _ @3 `# i2 V9 g, q - k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区
. f7 _8 K/ n2 p2 L, y3 C
" G; c. `$ v! w$ O- //映射ARM的核间通讯寄存器' _% ^! d, W/ [3 X% O2 q9 e+ v8 n
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
8 ~0 P8 r1 M: l1 n- J) A3 K - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);; {7 Y# {: g3 t! w, P" t) S6 k
- //将物理地址映射到内核空间
2 n, s/ v K" c3 h - mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);) q& h! \' ?# o6 m% B( H2 E8 L0 n
- //共享内存初始化6 E8 N3 [$ z1 R0 g' y: e
- SHM_ARM_Init((unsigned char *)mem_base);& t6 Y$ {; u5 X' H( L6 w
- /*申请中断*/
. g7 ]. v) h+ ~: H- {$ F1 X0 S - ) K8 v4 j2 j! P
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);: J8 y3 v9 o9 k! X- `. u1 j/ e* B# j
- if(result != 0)
! t3 ~5 n$ F3 [( Q - {
: ?" S) ^" o( W - if(result == -EINVAL): i& f$ B- |1 Q* S
- {7 F/ r1 g1 b' l) j9 m
- printk(KERN_ALERT "irq request err:-EINVAL\n");+ b5 i7 c; W( P/ w9 q
- }
9 |1 r3 n) N! j& `2 x8 Y h - else if(result == -EBUSY)
! ] G8 @# F/ B; i- A* H - {
/ E& Q7 S: u0 B; V - printk(KERN_ALERT "irq request err:--EBUSY\n");; ]# c) u C- a4 G
- }* @- T4 _. g2 ]. @ ], k/ P
- else
/ B( M4 b5 W; e - { x( _. u! Z, @: \: m. A
- printk(KERN_ALERT "irq request err: unknown\n");/ l* B0 ]/ T$ M8 ^+ j. _
- }
" e) i* K, x$ y. J - return result;
6 Z" W; W% [- s: M) ]) @9 ` - }% T+ M# n$ j: P4 C" ~7 ?4 o9 j3 F
- return 0;
& Y& m2 s8 f. k+ k - }1 `; Z7 ?8 |' V9 e/ l1 y- _9 n
- 0 F; e8 Z. {# k( B1 j) q% G2 ^
- /*设备驱动模块卸载函数*/
' g3 P: h- |1 Z6 f6 q% q% D - void __exit protocol_exit(void)
! o! e0 B I6 X T - {6 l2 p9 l$ c& F- z3 k- T
- /*释放中断*/0 w7 Z- B$ }( N% q" P
- free_irq(IRQ_DA8XX_CHIPINT0, NULL);
. ?! |. h4 ^6 N& o. L0 @/ s - //释放帧缓冲的内存% }- z, T. j E5 `
- k_linkQueue_release(&queue);" \7 {5 s+ j4 y7 C+ k) S) `
- //释放寄存器映射1 F4 V- ` W( H2 t6 d1 E6 O: a/ X
- iounmap(R_CHIPSIG);
: A C* B2 ~; p5 c" A' v' E - iounmap(R_CHIPSIG_CLR);$ @8 s0 ]; z7 B3 q8 I6 q9 g. q
- cdev_del(protocol_cdev); //删除cdev0 v& O+ K8 ~' n4 |& T
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号
9 W! M% J+ x: G; }+ C) Q/ i - device_destroy(protocol_class, protocol_dev_no); //销毁设备节点2 [1 O) F# [' n- q- b! M
- class_destroy(protocol_class); //销毁设备类
- J$ G. h8 u1 c# s6 w" U) U, a - printk(KERN_ALERT "exit success\n");# \: s8 S ~ u& d% m, o
- ' O4 K$ ?4 x* f+ w; h
- }) D3 Q/ I: Q1 T) y# P
- //驱动其他部分省略
复制代码 * X: K% n8 v# t6 b" H1 E9 k
R) k1 s1 P) f; [( D9 F+ x$ x
|