本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑
' n [* [8 U6 H4 w. K& D% H6 G1 K
项目要求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 n( y& ], {5 o0 _, W - ' `' K ^% m0 m( ~
- //引入其他模块函数和变量
' S* `1 w. M/ D- [" @, W - extern Ping_Pong_Buffer res_buff;
/ w3 d+ K7 y0 F8 Q5 I4 Y - 3 w' J' H: ^! M k' P& @' P! l% ?
- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列
- O) ]7 O! t1 |+ _ - extern void k_linkQueue_release(linkQueue *queue);//释放链队列
- D2 V4 A' ~# o" @* w - extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据$ {5 k/ I" V' m; Z- m4 s
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据6 U- B. W2 n& C& }" W, l$ p7 u$ d
; h4 \" z0 Y. [$ K ?- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化
- S3 i( Z" h2 d! t, T
. |) j: J. P7 V- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1
/ }) B9 ]" i2 y1 F; w) n - //设置主从设备号
8 _& a2 b& z q9 n- V - #define PROTOCOL_MAJOR 15 F4 R1 W/ D- x6 z$ J7 _
- #define PROTOCOL_MINOR 0: k- h& h# }, X" k9 j6 r
! z& \3 E7 R2 l- 3 O- I; V0 c5 H0 G7 {6 l) x
# m6 o: t* [. q- ]* h- //定义设备驱动的名字或设备节点的名字+ j0 ^0 ^+ ?8 m" }( G o
- #define DEVICE_NAME "protocol_driver"1 J& z% G. B z* W; F" f1 e
. \6 E* L1 j! I& K( R; z
6 w: S5 n# R+ d3 k2 \: z- //定义全局的循环队列作为数据缓冲区$ s' X! R) x+ D8 j% C
- k_linkQueue queue;) i( H! L9 }+ J8 }! Y9 U+ V; a0 D# m
- ) ], v9 v( t$ |& R3 m# t
- //寄存器地址映射全局变量7 S: g o0 B" \- @
- unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器
3 Y3 O: O& ?: n N - unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器
: X8 x6 [0 g( C( h: @1 E7 J
+ _7 ]' J9 u0 \7 E" @7 [- //物理内存映射全局变量
% K' j% k" k8 B- ^ - volatile void *mem_base = NULL;3 B: w D* K, _' V4 Q* h! Y
- volatile unsigned char *cur_buf_ptr = NULL;
$ X* e; U2 |; x - volatile unsigned char *data_ready_ptr = NULL;
, _& C# W- P c* Z8 U G - 5 G0 m7 q) y; a9 i% H' f `
- & e' u( u7 y' s; V( F& O, T
# ]2 l1 r' s0 C. S5 ]" `3 F- //定义读数据等待队列头,IO阻塞' k4 Z- T8 R+ L0 R+ e+ Z; X
- DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);; k9 s9 E1 Q# ?' ?6 o- a
- 1 p: j8 d1 |+ K' V
- //定义原子变量$ ]4 X- r6 O4 N
- static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备
: F2 i9 @7 h7 A _' f3 c3 c o
: N3 w9 \3 @- Q$ X/ k- P( z
) @8 l: ]' P) K- [1 k' n8 J( B- //定义设备类
Q/ v& P" F$ x# K3 T - static struct class *protocol_class;
0 ]6 M4 i! e5 { - struct cdev *protocol_cdev;1 a. V) l) k+ h3 G" L- J
- dev_t protocol_dev_no;+ D+ w0 d: i( o" _
- & b/ W/ K i; @6 l; ?
- /*定义tasklet和声明底半部函数并关联*/ [5 u: ~; E# d1 F# W) f
- void read_data_tasklet(unsigned long);
. V1 p8 w- G- p. w" A$ t - ( @) w* R- `' k
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);9 c7 I# f2 {* O6 `: C; U
- //将CHIPINT0_tasklet与read_data绑定,传入参数02 q9 E7 m! a0 h; S3 x- J) m0 M/ `
- + F2 L/ \) w/ V( g
- /*中断处理底半部, 拷贝内存*/
+ Q: e. H5 l7 Q0 n - void read_data(unsigned long a)- Q6 S" {! K2 J8 u6 P, j
- {$ b$ k$ z- I! }( j
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1
0 j9 Y- l, H3 g" G5 N/ q; b - {+ ^# `. q2 o, k$ X2 M. c0 b& Y" ?) s& c1 I
- read_quest = 0;
/ @7 [9 ~) [- c3 f - wake_up_interruptible(&wait_queue_head);//唤醒读等待队列' e9 @0 p2 K7 }5 k
- }" |, z( I& {' G: U0 i) P N
- ; M7 h& B' Z8 \
- }8 H7 X9 ~0 A" S' @( l! R( E
- 8 k+ u$ V2 [. h# g0 p" q1 R* ~( o
- /*中断处理顶半部*/ k V/ A# R% |0 J* X2 U; L3 |
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)
5 z6 j- A. a1 }4 [6 `' b; O* y0 N - {
# ~$ Z* d E. k% h; t4 K - //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
& x7 M) W1 f* d1 d6 u( \" ~& c3 T - volatile Buffer_Type *next_read;. i: x* B% C. A2 _- U
- //如果DSP数据已经ready( Y9 `% q# e7 i
- if(*(res_buff.cur_buffer->data_ready) == 1)" H; q7 h$ H$ U# L$ W5 b
- {# l0 ?- {" w& h% E8 t
- if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer+ F3 B8 T) \/ S$ _* R9 x8 v8 H
- {( k9 \) y! A; A# H8 r8 \8 m
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer3 L ~* F. L" O
- //printk(KERN_ALERT"read ping\n");1 h( D5 J" H( W! K p
- }
$ m; }# ?8 i) H7 m' M1 M8 x E- f. h - else
: W5 u5 ~6 J0 C( _' O a - {
* a1 m/ o3 h/ y1 K6 Z - next_read = &res_buff.ping_buffer;//下一次中断读ping buffer% C: E2 L" _' H& a6 Z" A' D
- //printk(KERN_ALERT"read pong\n");# L5 i, L8 Q: d) a. J
- }8 i' d- w; F, l
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer1 U3 A- w* O( V8 |* T) S" |5 ~/ V
- //将数据插入链队列2 x4 W' V3 g6 z- \0 c' }, g5 v
- k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);+ z- J$ W; B4 H5 |, t# f
- //标识位都重置
$ u6 ? U' b0 z9 C6 C - *(res_buff.cur_buffer->data_ready) = 0;
`. o. \, L7 o; \/ S5 P - *(res_buff.cur_buffer->data_size) = 0;
: o$ _4 o0 {, v+ |* p2 _; D" k) s0 U - res_buff.cur_buffer = next_read;
. \+ q. y8 c. d& W9 q" _ - }. U* l) e5 L+ l' p
- //清楚中断标识5 e* F" s; }/ }
- *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status
. N$ S& h2 @+ A1 }( u, a. f- X, T - tasklet_schedule(&CHIPINT0_tasklet);//调度底半部 + p! ~3 ]) K k! \1 L; I
- 9 d7 b+ \4 p' |0 }3 K# \# g- A
- 5 ]' V, g: `1 w) e
- return IRQ_HANDLED;
# d! H- I6 W0 V) ~; D3 g: l6 P6 E \
% A" `6 S# `7 o! r/ ~9 i( n2 p- }
' L6 O4 T3 K6 h9 s- S
* C' D& v- s! B, o5 y( R- //文件打开函数4 _. [$ G* f. M4 `
- static int protocol_open(struct inode *inode, struct file *file)8 w2 P7 b% f% w3 N
- {
! o* H* e* T6 \( ] - int result = 0;: f7 r2 i+ c- X! Z% M9 e/ I X
- if(!atomic_dec_and_test(&dev_available)): L# ^/ H* g! Y8 w% H0 u3 X: y
- {" v' |/ Q8 }9 k- M0 U; o, _
- atomic_inc(&dev_available);
) v. U2 l& w% t0 _; ]* t - return -EBUSY;//设备已经被打开( k, c2 r* E: y& ^( F
- } w1 Z- E& e9 ]) E$ C% |1 t/ E0 l* L
- printk (KERN_ALERT "\nprotrol driver open\n");0 D; |0 \. h. y3 H4 R7 Y
- return 0;1 O2 f# L- ]# ^* i D
- }* [9 c! J: d0 S9 H
- . F$ W/ M8 x$ H: h8 z$ J' s
- //文件释放函数( \+ F9 N$ T6 w
- static int protocol_release(struct inode *inode, struct file *filp)
1 Y! M0 I6 n7 s - { m) s2 V& k& u6 T w5 I" Z
- atomic_inc(&dev_available);//释放设备,原子变量加18 f: H* t- F, K5 O, ?
- printk (KERN_ALERT "device released\n");
/ g& f" T2 j; }# Q% W8 H+ H/ K; L - return 0;4 \+ W1 Y* W9 \1 x% B" Y
- }
4 y) C% r9 e* d8 `5 F+ M - : G' b* w7 |% U& ~' {! \
- //文件读函数
7 H9 t& S* g6 J( c. O# I% ?, l: n - static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)9 g- W D% I! D( |0 U- N
- {3 Q j" F- K: n) r2 l7 ?/ D5 r# Q- G
- int ret = 0;, h* m, s2 i8 |6 C( I; h
- //定义等待队列
9 {( H4 V4 W7 k$ p0 q4 F - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列) b r8 @8 N. l* S6 m# c. H& L
- add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
' m' G# b$ o3 w# ~8 ? - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
( c4 u5 a4 H6 Y! ^ - {) `! |. O; t! {7 [9 g0 `3 ~* C D) Q
- //printk(KERN_ALERT"\nbuffer no data\n");
, T. M$ l2 G$ @0 L% k) S/ m - //如果是非阻塞方式读取,则直接跳出+ U1 Z4 ~, f* ]( W5 F% W! @
- if(filp->f_flags & O_NONBLOCK)5 ? [2 x% z% m5 a) L/ E3 ?
- {
$ E* H5 M! N$ q# D, e+ Z. B; C - ret = -EAGAIN;7 d1 O( D! P4 z: Y! n- ^! ^/ F& J. K
- goto out;5 F8 y; O" d0 r" {: a! z4 |
- }& F# H, g7 k# L. r9 l& W( f
- //阻塞当前进程,放弃cpu资源
) }" `( }$ {& q9 T0 k: m - read_quest = 1;
, I7 s2 w4 F0 d8 K: X3 H - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠8 X0 Q4 |' L+ J4 s$ D& u1 u" a
- schedule();//调度其他进程运行
6 Y% _" s R" O/ }8 x - if(signal_pending(current))/ m1 P6 Q' ~) u; c
- {: M. b$ Z: ^* K9 c% J S7 {/ C
- //如果是因为信号被唤醒,则返回到系统调用之前的地方3 s& L5 \$ w2 V3 e* M" Q
- ret = -ERESTARTSYS;
9 j/ {0 R/ Y- c4 M - goto out;
! k3 l3 ?3 j, B/ J - }( V2 k- s0 U& [' F5 }
- }
0 C. k2 W, W5 F0 O l5 L- S1 M - //将数据拷贝到用户空间' S# A& I& N8 ~5 n! g
- ret = k_linkQueue_getData(&queue, dst);
9 z' Y m+ p; d) L( Y: j; Y - if(ret == 0)
, S. ~' X* `2 A7 j; |) e& { - {; h) v, ~1 Z. h7 r0 Q( k0 U
- //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
" A8 e& u& s1 o8 t0 C: w - }
9 t. C2 U- V, f2 c" [4 d - out:
8 l a, D) r$ E3 C4 H/ B* j - remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列
, K5 r3 n k5 f6 P# \8 w - set_current_state(TASK_RUNNING);//设置当前进程为运行状态
2 j: M" e1 n6 ]% Z, ]! A* r* s - return ret;" G' E1 b Q& y V1 G5 o
- }
7 z7 r0 }: \; t( T% B( ]5 R: o0 v' K
9 I; Q8 R6 o# y t( z f
+ B1 B& T; b7 ~- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)
2 t9 J& T6 `5 o# i - {: e8 }0 z! ]& \* n6 v B0 k4 B+ N' D* y
- return 0;
/ h- y$ D) |2 k5 c/ a8 h6 { - }
o2 K* \/ R+ L - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行: Y/ L' l/ I0 x% z( x) }% R+ r
- open()、release()、ioctl()协同调用时被调用*/
5 h4 m1 U" f: G- X2 x! K - static const struct file_operations protocol_fops =
/ I' \$ e$ m# Q3 q5 k+ h$ I - {: |% }9 ~2 @+ L4 a# ?
- .owner = THIS_MODULE,6 s5 _# F M2 v9 t$ g
- .open = protocol_open,
1 ? w8 [7 @9 I/ y2 t6 R - .release = protocol_release,5 k! Z9 s" y ^* W
- .read = protocol_read,1 t' O3 | u' {# }
- // .write = protocol_write,2 K( B3 I; A7 N# i: Q2 u
- .unlocked_ioctl=protocol_ioctl,
+ r3 M% ?2 l# T - };1 }1 L8 L& j7 f9 q. w
8 X- e u0 v! X# `1 R) }. j# r9 N- /*设备驱动模块加载函数*/% l/ y, ~$ Y7 G$ r+ k) J* X# h# `
- int __init protocol_init(void)4 ^1 h# B2 C) m) P
- {
/ b/ ~; Q( Z" y" H$ J - int ret = 0;" r2 u! |8 j/ S9 Q3 t
- int result = 0;
6 v7 Y( y3 S$ B - //申请注册设备号(动态)9 C* I- J1 X! O
- ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); ) J# R \. A. K0 T/ d9 _# w) H7 |. s
- if(ret < 0)4 ~) ?, A. h; [) w7 \7 `3 B" `; B
- {
& G/ e- c; P" S# I - printk(KERN_EMERG "alloc_chrdev_region failed\n");* \, |) V5 P4 U! H& J
- return 0;; M( r* g5 j" y2 h( W! p* ^
- }
7 {# y3 F% D3 j* A: ^ - //分配cdev
! s$ m, B% Q g* ]1 q; D - protocol_cdev = cdev_alloc();) P1 x5 T# w: g. _1 M: f: O/ ^) w* ~& C) y
- if(protocol_cdev == NULL)1 L% v& {; U" N
- {
% a A7 B$ h0 I& C - printk(KERN_EMERG "Cannot alloc cdev\n");
2 m+ F* U0 V7 v+ m* O! n2 @. v - return 0;* @& \: N9 V2 T
- }
( F; Q( p1 v$ L" \9 i - //初始化cdev
& w" p$ C- C0 ^6 l - cdev_init(protocol_cdev,&protocol_fops);
1 S) M# `) j' C" p - protocol_cdev->owner=THIS_MODULE;3 \& b7 e, s3 _) b* X! M3 m) d- t
- //注册cdev% Y. P% m; M; J0 r$ r2 [# q k
- cdev_add(protocol_cdev, protocol_dev_no, 1); ( k% J1 Q$ Q! w! |
- //创建一个类' F0 i, W5 j: B3 i) M) K. R) Q, |
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);7 R" Z7 u/ q) e/ x! ]( O
- //创建设备节点4 V; t+ [/ F7 F
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);! c I) s9 Y: j8 `0 p( a
-
! [# S/ P, X% k - 2 T+ U8 G) M! c! q2 B, |2 A. I
- //申请链式循环队列作为缓冲区DSP数据帧的缓冲区& y3 T: v* N( l+ n9 Z7 P1 u
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区
# V v1 h! K9 P1 \ u! Z+ s0 I
; v; d( V* K' ?3 H/ t2 W' U- //映射ARM的核间通讯寄存器
8 O* W" C( b t3 B8 i - R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);$ a6 z5 w. h' d6 Y1 w" G
- R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);
2 k4 o" h# O( ?# n - //将物理地址映射到内核空间
( x2 ~" V! t- |9 m - mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);' Q% D5 m ~9 Q- i
- //共享内存初始化
- \2 Z$ I+ E1 r' { - SHM_ARM_Init((unsigned char *)mem_base);1 X* [! ~: ?+ C1 M+ K: u
- /*申请中断*/
; k- M! X1 ~, D
: N& t/ d r. Y! B7 Y4 K# k- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);
/ w d/ y8 [% z; F - if(result != 0)
% ?6 b. W3 |9 Y. c - {
& s o& S7 k# C A% c( e7 l* U; z - if(result == -EINVAL)% C# V3 K; G2 X/ b* C
- {" D2 ~! y. V+ E. [1 J( ]
- printk(KERN_ALERT "irq request err:-EINVAL\n");# K$ F" ~& P" {2 A# W
- }
6 {; l, o/ z" \; h2 X& c - else if(result == -EBUSY)0 `9 B4 f/ j0 }) G2 y; d
- {
( _) R; ?" E, z0 L- V" L - printk(KERN_ALERT "irq request err:--EBUSY\n");, p" ^) \4 |9 _4 B
- }
) X/ X5 L3 x5 n - else) [4 I/ s2 O% `" A" Z) h: P$ [% S2 a
- {5 `, M* ?0 V& }/ x8 G
- printk(KERN_ALERT "irq request err: unknown\n");7 q7 B0 s& K% ]5 j6 w( {: A; K5 r' l- r
- }0 |2 v9 t1 }+ R5 s* |% k
- return result;
6 c4 J! J# b e" s- m - }
- C. s2 R- }# L, D3 Y+ \ - return 0;
; Y8 C) ]8 j2 B, J2 E - }' J- H5 b- I# R; w" b$ P2 ^
- 7 e# I! x& c3 L5 C r0 O
- /*设备驱动模块卸载函数*/
' t1 t0 u3 _# c- i6 X7 g# k - void __exit protocol_exit(void)+ \1 K3 E* e+ u9 B7 N' W
- {
* a' M$ v& x/ [3 K9 n2 I - /*释放中断*/! J3 m3 r/ w3 E0 X/ t# k6 M
- free_irq(IRQ_DA8XX_CHIPINT0, NULL);9 r" M# O3 U& [
- //释放帧缓冲的内存: [* ]! `) s9 W9 i* \8 B
- k_linkQueue_release(&queue);8 p, G" [4 ~/ H5 V' [: A. B
- //释放寄存器映射
: m+ X7 i, o4 C - iounmap(R_CHIPSIG);
3 v$ R8 B+ A2 E) v+ _8 I- b) h' S - iounmap(R_CHIPSIG_CLR);
1 j; G% V1 o3 `, Z - cdev_del(protocol_cdev); //删除cdev
5 N2 E3 X" j+ j8 m6 A( w1 J - unregister_chrdev_region(protocol_dev_no, 1); //注销设备号0 C M) X$ S# A0 e
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
1 C7 n# u$ x2 H! }3 p ` - class_destroy(protocol_class); //销毁设备类4 J1 |3 |9 Y6 `4 w5 m/ V
- printk(KERN_ALERT "exit success\n");2 x1 \7 @5 @1 y3 H) r
- ^4 k" O. g- ~& x3 @, Y, k- }
( d$ ^. g9 C* u# \ - //驱动其他部分省略
复制代码
# R# A& m5 l S* c0 i0 X( x0 u& I$ f1 `& b( U1 c" a* _. A
|