本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑
% a: Z/ S8 z$ i1 `. Q6 b! N& t3 L; o3 J% X! n% M
项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略6 W& b" J+ L% M3 T2 K
- - c" b g6 ]; O8 W0 \- r
- //引入其他模块函数和变量
; `. g2 [3 f* s: g% ] - extern Ping_Pong_Buffer res_buff;0 R# M) C- G2 @& Z3 e5 O
( z3 c8 {' d+ b% N' C- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列
/ c/ E5 O3 x1 l - extern void k_linkQueue_release(linkQueue *queue);//释放链队列
% A: H( K& z- @- R) ? - extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据8 Q3 v9 Z7 O: d; c8 J' Z
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据
) Z" [0 ]4 C2 K* Y; K
# ^: T3 L6 j# W0 p2 b8 h9 y- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化
. i- X: ]: M: c( X4 H4 t: |
. B& q/ \4 `- Y6 H; A% i+ ^- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1
2 a+ e/ W( Q4 ^& Z - //设置主从设备号 s8 w$ @* r; H
- #define PROTOCOL_MAJOR 1( p) i' p$ u/ a/ c w
- #define PROTOCOL_MINOR 0& a0 C+ a* L, {! e6 \8 Z
& l, v7 W# B- M7 q, j: `9 _- 7 [* Y e0 D; M
, i5 y4 J( R3 C. U! D! M- //定义设备驱动的名字或设备节点的名字, |: Q5 M3 F9 K" _, a/ v
- #define DEVICE_NAME "protocol_driver"+ n/ x8 B. k/ A# W3 q. {$ L' m. V
- & B6 k# q7 _' A9 c3 X/ f) |
[7 g+ l) n1 B% i6 N- //定义全局的循环队列作为数据缓冲区
. R+ u/ r1 D/ S9 h# J/ t8 U$ q - k_linkQueue queue;# [6 _' f* `/ S" Z$ o' e) w# W+ D! L: Y
- 4 m: [' N2 p2 ?, [4 u1 ]3 I- ~9 j% s
- //寄存器地址映射全局变量
7 E2 Q/ [# r# v4 [, N8 w# H' r4 ^ - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器1 Q) v, C _" ?$ B8 P4 {- i
- unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器$ j8 M+ N0 B8 ~- F0 y
) [, @' F. H# C- //物理内存映射全局变量4 t" r% x5 i5 O8 c% j# w: \
- volatile void *mem_base = NULL;
6 `( g& Z* r9 _' j# o# w6 C$ q - volatile unsigned char *cur_buf_ptr = NULL;
+ z' w5 ]8 G8 J4 ]8 t- `, A) }* Y9 x - volatile unsigned char *data_ready_ptr = NULL;6 t4 i* _1 ^: L# h+ Q
- & r7 Q+ s& v! r5 i4 h1 }
; Z/ _5 W* Z/ Z$ |9 A/ ~/ p; R- % }* ]" Z; d4 f" a
- //定义读数据等待队列头,IO阻塞
# S; I9 i9 y- u" f7 z- a - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);
+ b; f: p8 D' N: g4 {! B
, [: |, l8 X* q& i6 g5 Q- V2 Y y- //定义原子变量* R$ r# { Q5 ]$ f. t, y
- static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备1 C* I& i0 @& P/ [9 I1 u
4 E. \+ u& y! S( F& e- ~4 X; M- & f3 w- v5 T6 w: h+ M, d& y+ {
- //定义设备类
. q6 u2 o* t3 w2 O" i4 l7 S - static struct class *protocol_class;
& v4 c- O4 i, `: M! x2 a - struct cdev *protocol_cdev;
, [/ o9 E: o2 a, H; n3 y& ]7 L - dev_t protocol_dev_no;" ?" x) ]# X# A: U+ k9 j2 E
/ u( E5 L' C3 u# f* W/ f! D- /*定义tasklet和声明底半部函数并关联*/
: y( Y+ k \1 M) C% l* E3 h5 v& [6 ? - void read_data_tasklet(unsigned long);
1 U% G9 y8 I9 S: e' W
0 T3 E; w! Y. y$ \9 B+ O- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);; A3 m' Z/ ?* k3 d* b% r8 ~9 L
- //将CHIPINT0_tasklet与read_data绑定,传入参数08 z7 r+ L1 C; N% Q# ~. T
- 8 \) K" Q P: F$ }) l
- /*中断处理底半部, 拷贝内存*/
- u& \; E& g- @9 c8 E; p& v - void read_data(unsigned long a)
* U$ h1 v/ K7 |7 x - {
! G8 P0 A9 u+ |+ K - if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1
1 L$ N# e3 C) c8 M: F7 ^7 C% g - {
; m z% v9 b+ q - read_quest = 0;
y" n* M1 c# @) c- q; L- g6 i - wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
! ?, X4 q- q0 f: { - }6 `1 O+ j' k& P) u& Y1 V) G
4 r3 J/ c8 x" c+ o' p- u- }% n) L# G8 d+ `" m3 k( U
- . m2 Q- B C$ Z \
- /*中断处理顶半部*/" n7 K& O4 `; g* {8 U* h; p7 ~
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)5 m# C0 }( H/ n
- {
/ {$ n1 }* S: Z- y - //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
7 B( {! V- i/ o% S- H9 s. n - volatile Buffer_Type *next_read;; `3 H1 E. ^, D) S
- //如果DSP数据已经ready* ^- n% a, c% Y |/ A6 Z ]
- if(*(res_buff.cur_buffer->data_ready) == 1)( w+ t* j! h, @: x {" k( b
- {
' M; ~% L; w0 Y: a* j. L) o - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer
V1 M0 X4 F% Q5 Q - {' u" C! h/ B; _& h; c
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer
" b I3 S4 a, b: a6 I U$ P - //printk(KERN_ALERT"read ping\n");
1 M7 |$ \/ i$ Y; Y+ N - }0 N* t. R* }, V5 v1 q$ F
- else
- x' X: w. E* F# Z# _ - {
7 l$ Z5 H- U% k4 A) } - next_read = &res_buff.ping_buffer;//下一次中断读ping buffer
6 |( \/ x @) k5 i" n - //printk(KERN_ALERT"read pong\n");
+ z! x# j4 M5 v W/ { - }
* h" C9 h+ |' _' \- h3 L - *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer$ U+ T5 Z8 H/ o/ x! N9 \0 Z% d
- //将数据插入链队列
* T) n, }3 F( W" Y; C - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);+ n" e# X' s2 X O6 i
- //标识位都重置7 Y( O7 V' ^4 m+ z: R( Z
- *(res_buff.cur_buffer->data_ready) = 0;
. ]: @6 n! d- P1 l+ ^) L - *(res_buff.cur_buffer->data_size) = 0;# d; O9 O7 C3 P
- res_buff.cur_buffer = next_read;3 P8 _9 s. V( b
- }5 F2 v$ p6 ]7 m
- //清楚中断标识
. r ?2 E+ H2 H; a# P - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status
. l/ O3 T% A# [, d+ _/ o4 L8 | - tasklet_schedule(&CHIPINT0_tasklet);//调度底半部
- Z- A* }: Z" X% T - 3 j, j" ~# v0 M$ U7 [
/ t0 @- C- G( p% E& h- return IRQ_HANDLED;
! q2 w6 t& p, u2 ]/ K - $ c9 ^" B5 @0 M; p' ^" H
- }- X$ `0 f0 c# X! d+ L
- 4 F* W% d: x8 I! m4 N4 V% }- {# F
- //文件打开函数
0 g) n% z! t* P5 r# f5 [/ G4 h - static int protocol_open(struct inode *inode, struct file *file)
4 X3 I: k$ `3 U. I/ K# _( H - {6 ]. V# s: N. T1 ~6 O
- int result = 0;4 J7 B5 G7 y# p$ B: o* m) Y6 _
- if(!atomic_dec_and_test(&dev_available))
& [3 A0 [- z- Q" s8 X4 g - {& F/ C7 `' Q: @. X6 L0 G3 l
- atomic_inc(&dev_available);+ I+ B8 {9 j' L" ?6 j* }
- return -EBUSY;//设备已经被打开# i% Q: |1 X/ i& t! D5 ~
- }" p8 S) [+ X) `2 h
- printk (KERN_ALERT "\nprotrol driver open\n");6 o5 }5 r! x- ]! |
- return 0;
o$ W7 b ~* I' o; T: k - }+ u" K. L: z: C( E% f4 W
- $ p% z( S; f4 ~8 k. x
- //文件释放函数
) J* n9 A5 W8 E8 i - static int protocol_release(struct inode *inode, struct file *filp)
. T" ?" E# m5 t$ H* m& P1 A" E - {
& o1 D0 N @: X0 ^+ A1 v. T - atomic_inc(&dev_available);//释放设备,原子变量加1
6 u m$ v/ L% R9 g$ o - printk (KERN_ALERT "device released\n");; B/ Z6 I' }# B, Z% [; b8 g! T
- return 0;0 T* Z; z5 u4 m1 s) H5 t+ N
- }
y- h- c( c5 W- l - * B2 S0 f$ V2 [- c$ b
- //文件读函数& Y K3 k) g, j( M$ p
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)$ K, m9 _. J# o! B
- {
" \7 ^5 q2 H" V. h1 @ - int ret = 0;
& }9 k& C7 l$ Z3 | [; ? - //定义等待队列
4 Q# z" L4 ? h - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列1 }& R9 o0 B4 ]4 V
- add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列6 H# c5 Y- v. Y
- if(queue.remainNumber == queue.blockNumber)//当前buffer没数据6 E) s) z+ H. l* W- A1 q% J* _
- {
; @! B! K* j, ?' a( x3 R - //printk(KERN_ALERT"\nbuffer no data\n"); _0 |% P, ?5 D/ t; T
- //如果是非阻塞方式读取,则直接跳出( @, D0 A. p4 P$ Y2 l
- if(filp->f_flags & O_NONBLOCK)
9 o5 p& F' E- y6 E& ?& q0 M: j# A - {
8 @& Z( u9 A! O t) V6 P2 d2 ? - ret = -EAGAIN;
6 O2 Q0 Q; S+ F' G$ b/ q - goto out;
9 @( d% [, l% |( }' `% B - }5 I o5 {; H' X- z7 Q* G
- //阻塞当前进程,放弃cpu资源
% I" l+ t D q$ V+ B: b& ~$ ] - read_quest = 1;
5 k, }2 s5 h* |7 k- P+ F - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠% s% |6 ^/ h" q' n
- schedule();//调度其他进程运行
! I6 L% {6 y% ]% p - if(signal_pending(current))4 P- u+ }3 x+ q, ^0 n- Z
- {
0 e! s8 f3 K4 o9 r1 W - //如果是因为信号被唤醒,则返回到系统调用之前的地方
, S* n& ~3 K' _# ` - ret = -ERESTARTSYS;
) F' D) `1 [1 o( M - goto out;
7 D# u* K; n5 p+ i; u: o - }
* t) Z- c5 E& [8 _$ Q( ^ - }
) T ]' j8 o; n2 B; t - //将数据拷贝到用户空间
! i4 A: F$ y( O/ _9 y* i! D - ret = k_linkQueue_getData(&queue, dst);% G* u- f3 v3 `% z
- if(ret == 0)
% e. P( P0 w+ P2 d/ D/ L - {
" S p0 T% O) L1 O1 O7 |( [ - //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
- S3 O% ~! |: c# G( i - }
4 r z. r* F v6 |) w$ [5 @' g - out:9 }( ]* c4 Z5 x% n/ ]5 {3 i
- remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列0 i( Z3 w# z7 Q1 b
- set_current_state(TASK_RUNNING);//设置当前进程为运行状态# {9 G5 ^" }0 [$ |' D3 E
- return ret;
* d" H0 ?9 u/ W - }
+ f1 d5 B9 @* x( f; w. a, J, \ E# g
! n% ?% [6 P+ ]! H# N$ f1 V8 i; Z* g- ; B* K1 E Q, X- j! m) Z
- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)
. y; l' A% y: R; Q# U6 M( L - {4 }- [9 s$ t T$ O% u- l
- return 0;5 r& }9 L8 j# w
- }
# l' s5 p9 V" |4 k8 f - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行) E+ A$ V7 x' A9 E( L4 z5 X
- open()、release()、ioctl()协同调用时被调用*/
9 h; I `9 x8 M* i - static const struct file_operations protocol_fops =, x8 S/ W! K" e2 V. s/ F7 _
- {
3 g& _ D: |; l* [5 t" E$ c: Y5 _ - .owner = THIS_MODULE,1 G6 z. `4 ?% W
- .open = protocol_open,' \: r% j: U) g( A+ M4 @3 \2 c
- .release = protocol_release,
( O, `; S! r2 f k; F" B* h - .read = protocol_read,
; h, V1 T0 I- T( W3 [& Z - // .write = protocol_write,
# w0 ^# ?0 M! y - .unlocked_ioctl=protocol_ioctl,
0 M9 g. Z( F+ F1 D - };9 h4 O |8 H b2 q. e1 j
- ) H1 L( Y. n8 G
- /*设备驱动模块加载函数*/
* ^0 `6 A$ n$ }7 s4 n - int __init protocol_init(void)8 f/ @# d; O; w0 K( ]" ]
- {7 g5 ]# e: @5 H! s# S
- int ret = 0;: f: J2 d3 ~, P: f
- int result = 0;
/ v8 B" N3 M0 x - //申请注册设备号(动态)- P. F5 _* t( b$ u! b
- ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME);
0 g2 x! H$ G" }# [* w# A0 z% h% q - if(ret < 0)
/ x5 r' Z- a- B! j% M - {
' N& `* A7 j9 W" ?9 j2 K - printk(KERN_EMERG "alloc_chrdev_region failed\n");
) t+ p2 } C, t$ o( `9 P* k' N - return 0;
, @5 Q; I n6 @, l: g/ m, A( d - }, i* t* m* \& _; n
- //分配cdev, O; L6 a/ A5 A! {/ |7 W- O( a
- protocol_cdev = cdev_alloc();2 S: {- W, ~; t: n% X8 M
- if(protocol_cdev == NULL)
' a- ]9 b# c6 N' n0 [9 g - {6 Z) X; [$ x/ g( U
- printk(KERN_EMERG "Cannot alloc cdev\n");3 n. f1 Z/ J/ \) w. J
- return 0;2 j6 o0 t9 \4 y
- }! P* @9 x! c3 T g
- //初始化cdev
: z, z: z: q8 w, i+ h - cdev_init(protocol_cdev,&protocol_fops);
4 G& i J2 h$ r8 e - protocol_cdev->owner=THIS_MODULE;
[$ v- @! r, { - //注册cdev
2 d3 H- v' A+ x# S - cdev_add(protocol_cdev, protocol_dev_no, 1); 4 b+ H/ a5 A$ Z* Y4 L3 f( d2 a
- //创建一个类6 L' z6 e- H; \9 @0 E8 q# H; a3 H
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);
" w+ j) W! J( k& r - //创建设备节点
; c7 ]3 H# ]2 E0 q z: G& ? - device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);
! D J/ ^: X/ I9 z d6 n# w2 X -
' f1 l% F" H, ~6 ^# x$ Q% c -
( F& Q/ P' w3 q( @; z+ K" D7 ]8 f - //申请链式循环队列作为缓冲区DSP数据帧的缓冲区
: j# Y6 B$ _$ E( |8 l* | - k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区# ~, x& m2 _9 {( L( F
. S! n7 p0 J, ]& w- J% ]+ o S- //映射ARM的核间通讯寄存器
9 c9 }0 b- p+ R2 Y - R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
5 w6 B* s) i+ [; E. `6 | - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);; ?/ W% h9 H4 A$ o
- //将物理地址映射到内核空间
" s D8 H6 J- v' a/ r5 z - mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);
+ H" `2 c6 }2 R; l9 U& `$ a; }( l - //共享内存初始化4 ]; Q. {4 i9 v
- SHM_ARM_Init((unsigned char *)mem_base);) x+ h8 H' w/ N4 W
- /*申请中断*/: g$ L( I+ I, r, q& F: j
! C; O, n) q5 Q! v' V' M7 v/ _- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);: P9 \1 L& M1 `# p/ T& C3 h6 v
- if(result != 0)
6 N/ E7 g$ ?! r- |; r. s1 { i - {
- [: y( V: T4 p) I; U - if(result == -EINVAL)1 {& e3 | m" C, p& x
- {
* h3 I5 B2 X% \+ C s+ i - printk(KERN_ALERT "irq request err:-EINVAL\n");5 X# T+ Z3 a, h5 g8 y6 i5 p
- }
0 Y1 F |8 i2 i A/ d - else if(result == -EBUSY)# H1 q& J" f/ w7 ?: h x6 ]& U+ P
- {6 D& O/ u1 g2 \( N3 }& {
- printk(KERN_ALERT "irq request err:--EBUSY\n");
# Q2 p- J6 q- D; |; N2 l - }8 @( c( P3 y' Q0 @) c d/ V E
- else! X, z4 M! Z7 A) T- l* @
- {
3 W$ c4 D; P. u+ l - printk(KERN_ALERT "irq request err: unknown\n");
: {4 o( k$ T0 g+ D S. l - }9 t0 ~" J; O8 l# X: A4 e1 O
- return result;
4 h- Q# T# \4 H0 @ - }
+ [" m' G& a9 ^( b! r% U; s" @ - return 0;% n$ p8 [1 h' p% ^- Y4 A
- } T! A: [5 s6 H! A/ k4 k Q
- $ n; Q2 f3 p- h0 V4 L
- /*设备驱动模块卸载函数*/
1 p- B5 n. n- f0 G/ q3 D8 S5 C - void __exit protocol_exit(void)$ d4 e6 `7 q' P
- {
' |* g K) M4 t" y - /*释放中断*/
2 n# L1 G: Y2 M$ n - free_irq(IRQ_DA8XX_CHIPINT0, NULL);( R, H: z. o2 q. h) C6 W1 ?
- //释放帧缓冲的内存) T- \7 i9 G8 v4 e1 ^2 t
- k_linkQueue_release(&queue);" }) J2 B% O6 A: E6 ^1 S
- //释放寄存器映射
- A4 @/ S- h/ S - iounmap(R_CHIPSIG);# P1 |6 M7 f7 ~; p& I& P
- iounmap(R_CHIPSIG_CLR);/ m& H/ f8 v( j. L
- cdev_del(protocol_cdev); //删除cdev
+ J4 ?5 c, `+ `% S' G% U - unregister_chrdev_region(protocol_dev_no, 1); //注销设备号- A. {& m, Y' x# ~; h/ ]+ ^
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
0 o" {4 a! q0 ]: \1 P( O - class_destroy(protocol_class); //销毁设备类
2 b8 [# W) L8 Z# q# g6 y# P) w! ~$ d - printk(KERN_ALERT "exit success\n");: ]6 e4 B& d0 i' ]! A' U. ?7 X
- + ~5 C5 |7 T$ d9 H9 ]" q
- }8 C9 ~& Q; {% g3 l/ m/ }
- //驱动其他部分省略
复制代码 ) |# o1 {5 |8 G0 L* g
- U: n0 R# z2 E7 _5 S
|