本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑 $ q; f \* N0 j. g
/ F/ E6 ]# B* g; l/ w项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略9 g7 @8 V. g6 @! T7 M4 Q. w
- 5 C9 z! Q7 ]. X- P+ f, Q
- //引入其他模块函数和变量2 A; W4 ]3 b, {( w, U
- extern Ping_Pong_Buffer res_buff;9 G) H* W/ z0 b, _0 v
( b2 q$ [" Y, r& _ j4 s+ u1 ?$ w4 N- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列
) E6 Q: U/ {- ^! Z - extern void k_linkQueue_release(linkQueue *queue);//释放链队列# E6 a/ j, j. ?# T- A
- extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据
/ I2 P3 o8 ]; x9 _2 S9 [$ e - extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据3 w( i+ c) @' T$ {* ]. K4 M
- / ?1 E& X: ]$ v' A: {7 B8 A8 v
- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化( e) Z U2 p' S! W
, y/ z' T% D% H. H- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1- [- D; J0 |9 i- q
- //设置主从设备号- B/ p: F1 ~& p0 x2 D
- #define PROTOCOL_MAJOR 1
- o/ `$ T; n# p9 L - #define PROTOCOL_MINOR 0
% g- ?* | { X/ d5 L- |
' m, W8 c8 J! E! H) P6 e- / F5 M# |( G$ d
- 9 q" H" U8 _' E: F- V/ |1 p
- //定义设备驱动的名字或设备节点的名字
% P% O0 Y Y9 Z' N) h$ S z7 q4 b - #define DEVICE_NAME "protocol_driver"
/ F. w' x9 a7 S5 l6 T - $ I8 c) X& |( Y" I) m% j
) h* e2 P' u$ y2 X T( [1 F7 S% N' t- //定义全局的循环队列作为数据缓冲区$ h P& t' k. Q x
- k_linkQueue queue;; }8 m7 p* y! F
- ; o1 P6 `3 P: v
- //寄存器地址映射全局变量
. o4 w$ b: a6 |4 d3 a8 K9 i - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器9 l& e/ ~7 o3 T$ e1 `: n
- unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器
/ N9 Y7 d5 R7 X0 M( M - 1 C' i% T4 o% G! z% G
- //物理内存映射全局变量
" G! U/ E% K& E j8 ~ - volatile void *mem_base = NULL;* l. X( A9 F+ z S
- volatile unsigned char *cur_buf_ptr = NULL;
9 n$ w( j' p0 }7 A - volatile unsigned char *data_ready_ptr = NULL;5 w- L8 y. @8 |
* @0 o" M2 y& H/ o8 @9 ^: M8 m- , G7 v) L7 ^$ h8 G
- 9 [$ r2 O! {* D
- //定义读数据等待队列头,IO阻塞
5 d* H: z( M7 P, E3 k. q - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);
# e; T D) D+ {% k1 J
, T4 e0 {2 `$ v% e- //定义原子变量- `7 Y) O8 A! Q
- static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备
) M3 n5 O; `* P" u2 M6 z2 Z( A! r- i - + S6 B$ s8 d: M# d. s
4 o: \2 k% s+ b# L/ m- //定义设备类
$ q# c1 j) M! D% p* c* ~ - static struct class *protocol_class;+ n4 A/ c" a1 l; q5 Y
- struct cdev *protocol_cdev;
: q, c+ a# Q2 e: w - dev_t protocol_dev_no; o; M8 `/ R0 v, h% s1 _/ v: [& R
- ) l' C: e3 n. g& V5 ?# H
- /*定义tasklet和声明底半部函数并关联*/
6 \6 s& l9 W1 X( f0 z; V& m - void read_data_tasklet(unsigned long);
! V. Y; P! d K$ U3 ~ H# i! M" t - , o+ A9 F4 Q: d: w
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
# x. o! Y3 b$ @% o4 l - //将CHIPINT0_tasklet与read_data绑定,传入参数0. y1 K, ` x/ q: _$ l% x' e
- 4 Q2 N' }& e- m6 L$ @+ V
- /*中断处理底半部, 拷贝内存*/
6 v) e3 J7 G1 Z$ b6 R - void read_data(unsigned long a)
, q9 d, \( r7 o( A2 W7 I# v9 h - {% I8 ]8 A% u; x) j+ J+ s9 e1 n
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1* p' B5 \, K* R& X" }/ s$ o
- {' G2 t; t) v( A- d
- read_quest = 0;
- X) R& n8 ]1 E - wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
% I, m' Q: L! V6 G' J$ c - }4 w4 \9 v+ J9 z+ a C" q
- m6 U4 ] T- A7 }6 g- }7 k! g& `" z9 ^, e! d) H
- & U, d( w1 c/ y2 S6 q
- /*中断处理顶半部*/8 Q7 ~6 }* D/ u6 g$ j
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)6 I1 L) {! l9 Z5 F2 I
- {
3 A$ k7 ?2 k6 B) K- Z3 [) ]/ u: l - //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样; O0 [& r6 P r6 U- T% ?2 U" d& X
- volatile Buffer_Type *next_read;) R* O3 n6 X2 m3 J0 z; O, y
- //如果DSP数据已经ready7 |( W& O) C2 h
- if(*(res_buff.cur_buffer->data_ready) == 1)# d$ b$ w! R8 p: r% a1 m
- {
/ Z! h$ `0 D& L* ~2 c, [0 k - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer: {6 Y, x2 u* m3 o
- {) R, o: c( D& p) M4 o
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer3 Q( X$ `5 n. U: X
- //printk(KERN_ALERT"read ping\n");
3 W& E% Y2 Y& f8 L4 s - }
! l. }* O# F3 L& ?% m4 L' V" _/ E - else
) N% n/ ?4 O2 @! y4 k - {* T; }9 u4 A: a+ P+ T0 W W* c
- next_read = &res_buff.ping_buffer;//下一次中断读ping buffer
4 F6 \/ @$ p7 u& l - //printk(KERN_ALERT"read pong\n");. z% G5 e/ N, P0 F! L
- }4 C+ x7 } U: W. a$ t. j
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer* E1 j. Q3 q) l
- //将数据插入链队列! K: P+ c, W& r3 a% e7 L$ A
- k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);
0 A+ k* d8 r- \" b* X8 r - //标识位都重置
* H( P7 a- |* c7 S, n( u: j - *(res_buff.cur_buffer->data_ready) = 0;" f: n+ [( H' E0 a
- *(res_buff.cur_buffer->data_size) = 0;
2 T! W( s2 z2 U% |; r% c# C - res_buff.cur_buffer = next_read;1 C3 P& m5 s5 e. T" }5 e, h$ _, N
- }
6 T4 _! c# Y4 a4 Y/ |# K) W - //清楚中断标识
. O& Y) o& V# p) | d. D- K& y h+ y - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status4 G. W# H5 I L
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部 9 y$ C1 X2 t8 V7 L
' I- C- C, S5 G2 q3 }' r) k0 i4 h- ' \3 t7 l% X; a& F( d' u
- return IRQ_HANDLED;
. U0 l4 S" C; a& F4 W+ y - / a. [. T" c1 _ I+ Y1 n" t% P% M2 g1 W
- }1 s: L L+ g7 J% b$ Y& D* H
1 m+ d3 J/ y# k- //文件打开函数' L1 e1 i1 [! A- e
- static int protocol_open(struct inode *inode, struct file *file)6 Z4 V* C: N9 q$ t- {
- {
2 K1 n$ v" `! H - int result = 0;
1 g0 ^6 \, h/ e/ g+ h. T' | - if(!atomic_dec_and_test(&dev_available))
" H& E) Y5 @/ Y& m4 I - {$ K. K* N& Y8 z1 t3 y
- atomic_inc(&dev_available);
' n; f. ~5 H; B5 C/ @7 ~- [5 ? - return -EBUSY;//设备已经被打开
; u7 e# f1 E% k" c+ A' u - }& W) }$ D% i, P
- printk (KERN_ALERT "\nprotrol driver open\n");! U# K' ~3 O' T" j" U8 y
- return 0;+ Q+ d4 T7 b$ _4 r" u T; G
- }9 Y9 | [- j/ Z% B8 H, e
- * R' s8 Q! t8 B8 c! A0 D3 L- N
- //文件释放函数
/ A0 S, m2 S0 K+ D6 o) b - static int protocol_release(struct inode *inode, struct file *filp)& q6 _( o9 C5 S5 _$ i& H! d" @; w2 e
- {) @3 G7 S8 V" P3 U; x
- atomic_inc(&dev_available);//释放设备,原子变量加1# H y E5 x7 Y/ C8 E( h
- printk (KERN_ALERT "device released\n");/ B" Y* q( u; R1 L& Q) R
- return 0;; _3 y+ @$ K. h
- }! y& G: {, e- M" F' o% b8 X
7 z( @: T8 H$ t0 y, \- //文件读函数3 F7 j$ G/ r4 L, |6 s/ F9 P# U6 E
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)
9 e% }1 J4 N: k$ I. `$ K \ - {0 k- J' X( e/ \5 g
- int ret = 0;# b# c! e1 ]6 X! ]5 ~
- //定义等待队列
" C- V$ t* ]( t% K' z - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列
9 o; H7 b" U/ f+ E0 [ - add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列) F1 `# d; A- G" d, z3 c% e% W; E3 b# u
- if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
e$ c/ k8 u5 h. @! G4 C, {& t - {
/ @" P# H/ Z9 ` h - //printk(KERN_ALERT"\nbuffer no data\n");( [. t, x: O/ a2 |
- //如果是非阻塞方式读取,则直接跳出" a$ i8 _) X" t* t0 D
- if(filp->f_flags & O_NONBLOCK); T( V, n: T+ n! M' B+ V8 p
- {
+ h0 O+ c2 T$ E5 Q" ?/ {( l - ret = -EAGAIN;
0 t7 [" [9 s- }7 q d - goto out;* m# q, U" m! M8 ^
- }- e. |4 z' ]. O
- //阻塞当前进程,放弃cpu资源
; D0 S' Q9 ] G+ U/ k - read_quest = 1;. t& y* `% X" w( T
- __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠+ ~7 l; f8 P1 H4 ^) `" u# M
- schedule();//调度其他进程运行3 ` c1 B0 W9 d8 n( {: }7 E
- if(signal_pending(current))
: F4 n, q# H, m! X( t - {; e& I2 S! ?9 R- b1 D3 L# L
- //如果是因为信号被唤醒,则返回到系统调用之前的地方
; j/ L6 L2 w1 m. o9 j; B) u9 F - ret = -ERESTARTSYS;( b! W) R3 Q8 |+ O% N9 @
- goto out;
+ X) a/ o- J) {# q% m - }' W) I6 r& O" s/ A1 x0 }( `& I) M
- }
$ n2 w: D8 m3 b: \5 b) v+ I - //将数据拷贝到用户空间9 u: Y3 D. z& S! N
- ret = k_linkQueue_getData(&queue, dst);8 P8 d! p/ ^+ ?+ r4 e9 A9 X# [
- if(ret == 0)
; t# D0 P4 ]& a& q - {
1 D! C0 q( }4 [7 n - //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
/ O+ D9 A% d- ` - }0 {3 f5 c5 j9 v6 Y) G6 v
- out:: z! W- e8 [# I, _8 u+ _5 v
- remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列' J- j' U; s0 j; o# ?. k
- set_current_state(TASK_RUNNING);//设置当前进程为运行状态
) f6 u! Z, s W8 I3 P" D - return ret;( r7 H5 J9 Y& I
- }
, x4 N/ f. o; w) m* n
1 A( w5 G. W% p* w
9 i3 D! B/ E. i. u- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)! a3 C% l" W/ d% b- K8 n, l+ o0 g: M
- {
; [2 u6 P" F. {3 x, S - return 0;
8 d! X9 S# B/ k1 \, _ - }
- u' }* K6 X3 `4 R# ~- Q - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行% G4 ^/ u* k E- p) P: B
- open()、release()、ioctl()协同调用时被调用*/% q& V# _" p6 z" ?+ |
- static const struct file_operations protocol_fops =
5 o; b5 d* }% }. N* U8 s& n1 K; R" k - {6 r: p/ @/ ]. O2 n5 S8 F) g
- .owner = THIS_MODULE,' s. }& u+ g/ s# T+ z# J; P
- .open = protocol_open,
5 F' E0 W% d5 O" L - .release = protocol_release,0 N$ {- ~ K4 k& \2 a
- .read = protocol_read,6 p2 f& I. Q+ P/ g0 R
- // .write = protocol_write,
% _1 z6 ~" e7 x- v - .unlocked_ioctl=protocol_ioctl,2 q9 e @6 N! R# p
- };* ?6 s& {+ W9 [
- \# c6 o4 R7 W& j& l3 M
- /*设备驱动模块加载函数*/, @; S e4 D" r' y9 [0 B
- int __init protocol_init(void)
% l4 G6 `# f/ v; C% ?/ N - {
: ^" {1 G8 o- w2 D6 C# Z+ Q- s: S - int ret = 0;
3 ~$ H8 J9 \, N. ~4 @/ T1 s - int result = 0;
6 s2 q2 N) u8 C& R4 y - //申请注册设备号(动态)
0 `8 `/ {3 }' V& |9 X4 t - ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); : }, }% U9 I; M C
- if(ret < 0)
8 S$ {' B! d! M" d' L" F% \$ @, S - {
2 a6 J7 o. r) c) {0 E - printk(KERN_EMERG "alloc_chrdev_region failed\n");0 p2 Q$ w- k/ S
- return 0;
( g$ e1 ^9 u3 X8 }5 D! e: f7 x$ B - }
7 v; P/ P5 p8 K1 B - //分配cdev0 {: G# q4 ? v, L9 R$ d# P2 e' L$ p
- protocol_cdev = cdev_alloc();
( p9 C& U& c+ s' D3 d - if(protocol_cdev == NULL)' ?% @1 O" k' m+ V0 v2 h1 A
- {# V! N. z6 ^8 d* D
- printk(KERN_EMERG "Cannot alloc cdev\n");6 T4 ~; w! ~2 N z2 f) `8 B# t* F
- return 0;
' C0 K4 d5 e# o - }
; l, e+ j Z8 I5 I - //初始化cdev
# s) i1 ~8 D2 K" [* Z! T1 Y: I - cdev_init(protocol_cdev,&protocol_fops);$ R' Y' x! A+ C( y- R
- protocol_cdev->owner=THIS_MODULE;
: S/ C, F: T% W1 M- j; R9 f8 A - //注册cdev0 S7 x3 e/ N& T- x: D- u/ K0 ?/ X
- cdev_add(protocol_cdev, protocol_dev_no, 1);
" y5 w5 K" O' l( b, F7 v" \* E9 V8 B - //创建一个类3 _4 G v5 E" ^8 ^# T
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);
4 @& k' Q' a$ u/ g - //创建设备节点' z* k7 m* y& r7 t$ ]
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);& j o1 E' V- u$ s v [0 T f
- - `& d0 I: \% P5 E$ B
-
5 r' a4 s4 D* D5 e) K - //申请链式循环队列作为缓冲区DSP数据帧的缓冲区
* U- b: ^2 @/ w, m1 y, T0 \ - k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区
9 l/ q% ^! A- i- ~7 O - , z* d! ~! K9 T( b
- //映射ARM的核间通讯寄存器
* ]# \ w$ L9 S$ `& n @7 {% E# u - R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
% V8 Q: F! K( m8 Y4 Y1 _ - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);/ u, g- Q9 M; q2 e
- //将物理地址映射到内核空间( C1 y; S9 f- L8 o; C' V$ p! R, }
- mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);
9 o% I* f) t* w, i3 X - //共享内存初始化: ~7 j8 s7 D+ ^5 O# n
- SHM_ARM_Init((unsigned char *)mem_base); l d2 l3 [1 R+ L. C& x$ X
- /*申请中断*/
1 N; o, m1 Q$ U, F - 9 X9 C' T X$ i, v5 W, O, H
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);
0 L3 `7 K0 C2 V# i9 I' D" I - if(result != 0)
8 u0 x& g( }6 W5 p. q8 {0 N - {
1 c4 `# o* X, ~1 x - if(result == -EINVAL)/ ]0 x1 J1 {0 ~' ~, B
- {- s% K' O7 [8 D$ s9 o: t# ]& j
- printk(KERN_ALERT "irq request err:-EINVAL\n");
2 @' ~* c3 K" Q- V - }
: F4 o) D1 s6 P2 c - else if(result == -EBUSY)
7 ~1 m5 i2 w0 Q, @5 R0 K - {/ ~/ x8 \" I7 B
- printk(KERN_ALERT "irq request err:--EBUSY\n");
+ n! l% k$ f9 E - }+ r' n& A* P/ u* {
- else
. E2 o, A$ n! V1 U# A V - {. y; g4 L. n' J w, T5 [4 i
- printk(KERN_ALERT "irq request err: unknown\n");" f( g! T( z* a+ p# r* j
- }
4 f% W S V) }% V! }& m - return result;( U9 P! |3 g* _* r3 R3 a
- }
1 r5 T+ w5 {( u# a: A9 F4 Z0 B1 r* F - return 0;
3 @+ y8 u. a) p# K! z. @! ] - }
. z# a7 H0 H) }" |# p' Y
. h, W. [! }6 u: P" m/ s0 T, [0 i- /*设备驱动模块卸载函数*/
- N; v, W3 H c; ]% a6 x - void __exit protocol_exit(void)
/ {- n9 S& }3 z3 @ - {! D+ P* y; S( k7 s9 _
- /*释放中断*/
; s# F2 Z, U. D, B) Z& ? - free_irq(IRQ_DA8XX_CHIPINT0, NULL);# K7 Y! r* b" n% F" U6 R& j/ m
- //释放帧缓冲的内存+ ^+ H. y, b3 M+ N5 W! m( Q
- k_linkQueue_release(&queue);# }; \% ~8 z, `2 t0 b
- //释放寄存器映射8 U: N) J _. c) d: v
- iounmap(R_CHIPSIG);
3 g! H& u* D1 `0 L4 `( [6 z/ S - iounmap(R_CHIPSIG_CLR);7 D9 V8 j0 c7 C4 C1 I! e0 Q4 i' V
- cdev_del(protocol_cdev); //删除cdev
; L; J$ Z1 {7 _" n: b( \0 P! L! W! W0 i - unregister_chrdev_region(protocol_dev_no, 1); //注销设备号8 H( M7 m: B3 v/ [' p3 I' G
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
* d# z" v2 e7 P: _# u* D - class_destroy(protocol_class); //销毁设备类+ [) i4 q0 x& O: _7 E1 ?6 C
- printk(KERN_ALERT "exit success\n");
l3 g6 n, H7 p! P* r& H0 ]6 Y& z4 K
# i4 g* ]5 ]/ v$ h: s, p0 p5 u' H- }+ U2 V) y9 T2 x- O' ? [
- //驱动其他部分省略
复制代码 9 ]7 [4 f& Y; U2 k5 w1 j6 D, B
) c% H. `$ R5 U
|