本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑 6 t8 X* _0 h* A. f! m
, a' a, L4 k2 P/ P. G/ h& F, z
项目要求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 ~+ ]# m+ J& a# H' H2 N$ x% q. O
- ' e2 m0 a. n8 H
- //引入其他模块函数和变量; U( K3 m, p) i4 l7 w$ P3 I- c
- extern Ping_Pong_Buffer res_buff;
! w) y% s* Z% t4 R2 k2 W - 5 v' J3 C& {7 k6 U
- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列
. P* X" ^, N7 y: I9 ~ - extern void k_linkQueue_release(linkQueue *queue);//释放链队列
+ ]; I% [" ]2 v. ]7 z - extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据: e9 q7 J7 c: ~8 N$ Y
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据8 j1 ^# I9 Y1 Q0 h1 f2 j
- @5 H8 Q" Y; n
- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化- |/ G' }/ p0 _ {
- % g6 F; m; H5 U# x: {
- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1
5 G; R4 `$ \; Z. K# L, `0 C8 {2 r A - //设置主从设备号
& K% `" n* q; M% a - #define PROTOCOL_MAJOR 1
. {6 q6 w$ ~/ M: p - #define PROTOCOL_MINOR 0
% R' N5 x' p: Q! P$ c+ v
( t' ]. C5 q l0 |# c8 v1 Z. _% Q- 0 G9 G+ q9 J1 P6 G
- 0 W7 N) |4 t8 t- v
- //定义设备驱动的名字或设备节点的名字- H# \5 a9 O9 b/ X* P5 I1 |
- #define DEVICE_NAME "protocol_driver"
) x# o, w( p9 e$ r8 s8 k% b# D
. n6 @* s1 a( R( ` b- 4 S, \) @0 \3 b
- //定义全局的循环队列作为数据缓冲区
' p4 d/ d* k' I1 [% N) M - k_linkQueue queue;. d( }$ B: X0 W
- ; |7 }/ j; j" z& r5 ~: [. a" O8 [5 R
- //寄存器地址映射全局变量8 }) n% E4 g }! [3 ~( @4 h
- unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器. J/ X ]( m6 x( E2 N: X/ v3 T
- unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器
: @2 |4 F( }6 F8 ^ - " y3 \/ I p( W
- //物理内存映射全局变量
/ Z5 C: H$ H4 G2 g - volatile void *mem_base = NULL;8 ?7 M4 k2 |3 i; n
- volatile unsigned char *cur_buf_ptr = NULL;
4 J( h3 C+ h S0 f - volatile unsigned char *data_ready_ptr = NULL;
: h$ h0 f% z- @' d0 ? - ; `# _ q- F+ W
- 6 v5 Y, a+ Y2 v3 `- B/ v
- " s1 w) ~) n0 L6 L+ R5 W+ {
- //定义读数据等待队列头,IO阻塞. |! m/ Y n9 F# }5 p; q
- DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);
/ q1 a1 Z" _: `9 T" K: q
) ~% X# A9 o# O7 u- //定义原子变量
4 d3 A- d$ P* z1 C! r" m5 P - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备
; C# i# ^" b8 O
0 ~( X- ]: g8 I
( i, r6 c9 x- u- r Q: Y- //定义设备类
" O. x8 w8 o. U/ T' f& f. a2 Z% L - static struct class *protocol_class;
" L& @! W& `4 w - struct cdev *protocol_cdev;2 L' b4 G0 l6 F. a7 k7 b
- dev_t protocol_dev_no;1 E& C. v% B5 K5 A3 \- [
- - R1 Z6 \) ]! O. t
- /*定义tasklet和声明底半部函数并关联*/
# C) k" t' [9 h- d5 |6 q- V - void read_data_tasklet(unsigned long);% H! G/ U. g- a8 C& N
- . }( Y- c" {8 @+ r3 Q
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
: r3 B7 b* a7 ^" m8 { - //将CHIPINT0_tasklet与read_data绑定,传入参数0. p3 k1 e7 v# g o( G. C1 a/ M* A: i
; `4 x1 R6 V0 [- /*中断处理底半部, 拷贝内存*/' e) g1 e% P9 z: A! o1 E* I5 `- T
- void read_data(unsigned long a)
: }* q4 R7 H' ~0 ?' l - {0 e3 W4 k0 e7 D8 [
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1: X" ^6 `, O. p$ K. j" }
- {' D8 C" S) v/ ~* U4 O- ]
- read_quest = 0;5 N* n" g/ k! r; W- g- w. m/ Z
- wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
& X% d, ^5 O, Z& r3 M' S - }- g$ Q) E0 H1 _5 O7 y2 Z8 y
- 6 ?6 g9 Z6 W% @! |' V9 h1 J2 }
- }( E* B, E3 ^# e/ W/ S/ f
5 P3 l. n+ }4 Q- /*中断处理顶半部*/
, ]- o3 C1 [% K' G T% a( c, r" t# C; p - irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)- D/ J3 I1 V/ r) r
- {
0 I' Y* _# |- E/ E - //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样/ |! O% y- p+ D
- volatile Buffer_Type *next_read;5 H8 U7 S' }4 M; p, \1 F1 V3 l, }
- //如果DSP数据已经ready9 a. |; P) x+ `! w3 Y$ c
- if(*(res_buff.cur_buffer->data_ready) == 1)
5 s/ M: T* f- J! t) [ - {
) C r7 ^. N& ^ P1 i - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer
8 O/ s# d% f6 ?5 m7 T+ X9 _ - {
7 e9 o; `# [! h# K( Z# H - next_read = &res_buff.pong_buffer;//下一次中断读pong buffer% I* M a O: d' J& l% j
- //printk(KERN_ALERT"read ping\n");4 ~6 A! q$ I; \9 w5 B3 a
- }
, T6 M; D: ~9 W" K+ U - else
) l/ F) O2 @; o! \3 d - {
& f! l: v8 Y/ |5 v3 u - next_read = &res_buff.ping_buffer;//下一次中断读ping buffer
# M# ]( M$ z" W/ S - //printk(KERN_ALERT"read pong\n");
3 y: [- ?! K; U9 D) x - }& c; F+ a' X1 @. L S
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer. d X7 V: U+ |. B# V
- //将数据插入链队列
. G( o0 E+ K l* Q, H/ \+ ~) d- X - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);
) U4 I! f- [8 _; Q5 ]1 C, F; V+ b; A - //标识位都重置; `8 z) `( v1 ?6 X9 f
- *(res_buff.cur_buffer->data_ready) = 0;+ @5 f; X- k+ q( T( m2 ?- e7 r
- *(res_buff.cur_buffer->data_size) = 0;) b5 P6 r, A+ j- L6 q/ b; T- I( K
- res_buff.cur_buffer = next_read;$ x1 {1 H- J0 r5 [4 o5 o* p; z5 g
- }. K/ p3 [5 {* h, V/ M8 \) U
- //清楚中断标识
, J. T, E, F" f$ B! Q1 A8 N: Y - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status
( L$ Z5 y9 M0 \/ ^ Q! [* M$ N - tasklet_schedule(&CHIPINT0_tasklet);//调度底半部 \) F' A/ h5 t) V6 v" W" @+ [
- # m" X4 L- M& y
- + v7 n/ Y6 M. e/ E7 K# \
- return IRQ_HANDLED;
$ d" U* [9 }# {$ I4 T V
0 b; x8 k' l8 K# q; U3 ~0 v. a0 t- }
% f/ R& A+ G" z P H
$ G( E2 u1 `. \ z- //文件打开函数
5 U8 P5 ~6 ^# Z5 Z) ~ - static int protocol_open(struct inode *inode, struct file *file)
V# w3 Z1 t+ T! V/ f% }1 @ - {# \8 X" V2 S5 L0 Z3 u
- int result = 0;
" F' c0 q" e8 t, j$ P - if(!atomic_dec_and_test(&dev_available))! ?1 g+ q$ O+ z4 ]0 `* z
- {
: N, a( V: E1 S& { - atomic_inc(&dev_available);. V9 e/ F8 L' K8 F0 A+ z( C
- return -EBUSY;//设备已经被打开- g% i# t% `- d# L! z
- }
8 r4 l3 j9 R! Z# s8 [ - printk (KERN_ALERT "\nprotrol driver open\n");
: v$ {; U8 B" m; U - return 0;
f# v4 m" k5 i' f& M+ l" D - }7 P0 {+ b/ I/ ]; G5 U# P/ Q- a
. {* C& }' f' ~- //文件释放函数
! h. v0 x+ A2 w! P# Q# X - static int protocol_release(struct inode *inode, struct file *filp)
: ]2 f0 X# X! R4 N - {
8 S8 p* w* o2 N( J2 L, K, a - atomic_inc(&dev_available);//释放设备,原子变量加1
/ |' N4 i' R7 ^3 F - printk (KERN_ALERT "device released\n");
; C+ s. N; A; r, }0 X - return 0;
: D% a; _5 s8 @0 Q9 a, |' j - }
! o/ u$ n/ e1 b+ X. g: r2 M; _
) Q! r' B/ H+ E/ G- //文件读函数; O/ I! p/ o# y
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)4 h: n0 _: x A/ z3 s
- {
) @& c# L8 F1 n* N+ w" Z( s - int ret = 0;( `3 `, D' E: B( p
- //定义等待队列# x( `7 z1 f9 | t/ W, U
- DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列- n6 f* a2 ^% Q+ S2 A i) w
- add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列1 ^) n8 Q E, V8 M7 w
- if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
! M! a* c1 E/ Q3 @. v5 h- Y# d1 R - {
- V) M6 G5 k1 y: N% g0 ^# {* q - //printk(KERN_ALERT"\nbuffer no data\n");
$ p; s5 z7 f4 E) l s - //如果是非阻塞方式读取,则直接跳出& ]: ~& A" ~5 {! W
- if(filp->f_flags & O_NONBLOCK)
Y- T& _- Q& X9 z: \ - {3 K9 L0 f: m' R) A( h3 g
- ret = -EAGAIN;7 Y2 _* I C& ~ v- r- V
- goto out;; r" E0 Y) D9 V( E3 r9 a' [
- }( `1 [; x2 U" f+ D6 ^/ d8 N
- //阻塞当前进程,放弃cpu资源% u9 p% X% w: o& p1 ^! K
- read_quest = 1;" M7 H b9 [2 V' Y7 b
- __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠5 K! I3 Y; k- N( b$ S) T
- schedule();//调度其他进程运行! b, l/ m0 |" m' a- [
- if(signal_pending(current))
z: M( j% U8 u. L& r# | - {6 }& V* ?8 m+ M% o+ J4 s! a7 O6 R
- //如果是因为信号被唤醒,则返回到系统调用之前的地方2 `5 l3 n6 h* T7 I& U
- ret = -ERESTARTSYS;9 i' j- X4 R7 h- E
- goto out;
8 B; y9 H/ E$ o e* Z7 I; y - }4 d0 [( M4 T) S- ^9 G
- }. `& n& P' a; C1 o/ _6 Z5 e) W
- //将数据拷贝到用户空间
' h3 p2 N' ~5 F+ D% `( j. x - ret = k_linkQueue_getData(&queue, dst);
, d& s, x2 K: Q, _4 V7 R. l - if(ret == 0)
1 M* u8 E4 i- L. F4 D* m7 B - {
9 H0 t) ?3 Q; r n/ c - //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);1 Z1 n& s( n! E+ ?: Z0 L
- }8 \% z3 H0 b) O5 m
- out:
, u0 k" n% v' _) x - remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列
2 a6 @* q, B4 `% Y( L4 W - set_current_state(TASK_RUNNING);//设置当前进程为运行状态
! V& S0 H3 a$ ^. ]& x - return ret;3 ^8 J* o; B+ j$ D8 P
- }5 ^) I! Q- \& h2 Q8 @' n+ e
- " ]0 T v3 v. _2 M- g( X
9 D9 o4 ^, j* C) G$ J y# O- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value); O. w4 e: d7 q( a
- {1 a, f: u, C6 k8 c7 z
- return 0;
. N, f" D% \; b' W8 z8 b - }
3 Q) j, j2 ]! L: E. G; h, L, Z - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行
* z7 N0 `5 L. u" |$ @$ |0 m - open()、release()、ioctl()协同调用时被调用*/
1 U. R6 ?8 z2 M1 x$ } - static const struct file_operations protocol_fops =3 N; d/ L( i+ X/ B' h |
- {
& ?* A3 I% e9 l* ~. {& R: ] - .owner = THIS_MODULE,
8 V% l4 I5 J* @: n' ?6 d P - .open = protocol_open,8 B4 J4 t2 r/ L& X+ I! @" k: D
- .release = protocol_release,0 j7 O9 U$ K0 a) F+ m/ P
- .read = protocol_read,$ z! J( J& G# t4 H9 ^
- // .write = protocol_write,
$ ^* q1 I- s3 Y o' H7 T* ^; T - .unlocked_ioctl=protocol_ioctl,* B7 d* d% K6 ], O: @; r+ K
- };
! {3 B% r2 {9 T0 \$ o% e$ c
9 s) @' G2 G6 B& Z1 e- /*设备驱动模块加载函数*/5 m) I7 E; [' P: E
- int __init protocol_init(void)
. c! }2 j1 n7 p: `: \ - {& |+ G9 g& ~7 R* F, D
- int ret = 0;; l, v+ M7 A8 W8 K# ]7 z
- int result = 0;5 W G( y8 [8 r: H9 C$ w
- //申请注册设备号(动态)
( ~0 o$ |; i) O3 J: x8 l2 c: g* V - ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME);
, G0 B! @& g; E+ R: b( B - if(ret < 0)' p, c [, F0 V
- {! t" M2 Z. l5 N3 e
- printk(KERN_EMERG "alloc_chrdev_region failed\n");
- ]* @" l6 X- x* Q - return 0;$ S8 v3 k: H% H: k5 ~2 B2 D/ @
- }
5 P1 W* X m; X0 ^ - //分配cdev5 V' _$ R9 A3 V9 ?( g$ e
- protocol_cdev = cdev_alloc();
$ L) A. }8 u, h5 Y5 \1 a6 d2 k - if(protocol_cdev == NULL)7 G$ H# D& Q& |8 }6 }
- {1 F! V: @% o v5 i7 M) T9 ]
- printk(KERN_EMERG "Cannot alloc cdev\n");/ u9 T) i3 u* }5 M- l3 n4 R5 Y3 k, r
- return 0;2 U7 U i& m9 ~! S
- }) k) ?. W* m& m5 T# C8 w3 q
- //初始化cdev; @+ w D, \5 p2 Z* ]2 r3 F Z
- cdev_init(protocol_cdev,&protocol_fops);& _+ @+ L5 B" Y8 o' F. T
- protocol_cdev->owner=THIS_MODULE;5 B# P) o5 I, {* c0 |& _6 i
- //注册cdev
6 x6 g' }4 A- M1 n% | - cdev_add(protocol_cdev, protocol_dev_no, 1);
' ^. n6 {+ X' E( s% x1 ?7 B - //创建一个类% ]) E; Q8 H9 C' z$ k( s" o f
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);! v# {' W1 \4 i+ h+ n$ n
- //创建设备节点/ {, S8 I. g2 ^8 M4 p! O9 v, P
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);/ e4 a& d9 N( }2 C8 c/ t. O: X
-
0 q: \0 B# ]1 N' E( P -
/ M! O; m5 u1 }; J1 N - //申请链式循环队列作为缓冲区DSP数据帧的缓冲区
- D+ U% z: ~5 Z - k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区6 ^# {% c" v+ V9 R; \" ]+ Q8 p% R
& E4 B2 l- s; i& ~! J% L% |- //映射ARM的核间通讯寄存器9 j0 |( _$ k, q7 o+ k
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
6 ?) K$ H+ o9 P5 \+ k' ] - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);
, p: i' f; q* Z - //将物理地址映射到内核空间6 N$ A+ ]; v' e0 Q- S3 S7 r2 L
- mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);
4 e/ U [) L9 j7 A2 F: J6 z - //共享内存初始化9 ^$ z- O5 U- O% n, T
- SHM_ARM_Init((unsigned char *)mem_base);- g# v- z$ O. k" {0 `$ P5 L5 X
- /*申请中断*/
3 S# a. i8 N2 k( \7 F; h - 4 [" k/ U% g- \
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);2 ]2 a6 c, ^( F+ ?2 u
- if(result != 0)6 K- h+ a: E: `: V6 B
- {
! ]8 K5 l' r7 m! h" E r - if(result == -EINVAL)3 T) h8 _- W" J& S# {+ G* H8 @
- {
' Z5 z+ Q! D& _ - printk(KERN_ALERT "irq request err:-EINVAL\n");3 F! H+ P9 h- z' x
- }
+ j8 _, j ]3 i$ D& A5 Q - else if(result == -EBUSY)' n; F. Q& C$ A w
- {
% B, I x6 ~$ ?* V - printk(KERN_ALERT "irq request err:--EBUSY\n");- X" C% W' s, G) U- y* V
- }
( u) r* g5 j% }7 F7 E' n O/ S - else
' B- U f2 M" z$ _) y& J: B - {
' q4 H. U0 }- f/ f - printk(KERN_ALERT "irq request err: unknown\n");
9 \0 E! V; z; G: e4 n" Y3 t - }
$ W& W0 L0 a' d: a$ \- P/ K$ B - return result;. e$ m/ S) r; x. c7 e- U* m+ F
- }
* S5 n* i" F4 `- E - return 0;
) r8 A. v2 Z( X+ I# L. _ - }
# n* |. Y/ p) }& \$ Q
: n5 H! N, T9 J v$ C7 O- /*设备驱动模块卸载函数*/
9 o, Q: n- C0 W- E% [4 b' k' i - void __exit protocol_exit(void)
+ G3 i6 u5 P b+ ?: M# ^ - {; X8 o$ D% f% C/ r r
- /*释放中断*/; c" S0 n( g- N2 F/ Y
- free_irq(IRQ_DA8XX_CHIPINT0, NULL);2 N# t4 p4 [) A j: g; a& D
- //释放帧缓冲的内存, v4 ^ k! _; E1 p0 }1 v1 w. {
- k_linkQueue_release(&queue);
4 C, d2 @6 Z( ^) s* Z - //释放寄存器映射) [& c$ w7 R& l7 a# V$ p
- iounmap(R_CHIPSIG);
; I$ H- D( i& u$ b M - iounmap(R_CHIPSIG_CLR);* ]) n9 P4 P$ ~8 [( R
- cdev_del(protocol_cdev); //删除cdev5 ^) w+ h1 s/ ~( o7 s
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号
" U% W* K2 i/ W9 X& f - device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
1 D4 y0 `; `4 j - class_destroy(protocol_class); //销毁设备类" x0 ]0 J1 F* X4 l! m7 U! L8 a
- printk(KERN_ALERT "exit success\n");
1 M% v. x- Q0 v7 Y9 r( o2 N* }+ E
8 w3 S8 Y q) x2 u* F, U- }8 E! I4 s3 o2 X# |' E9 N1 X
- //驱动其他部分省略
复制代码
w4 Y/ G* A8 H$ Q/ t& ^/ x2 R& N: ~: L1 u0 @5 E
|