本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑
( A0 b' l$ V$ q% s) b. I
, r" z4 T3 d9 e- 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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略
5 E J k M0 l; L
, \* j7 ]0 Z) m3 M: @0 N! V2 H' k- //引入其他模块函数和变量+ r0 U' ?! H+ U0 d" b$ @1 l6 _
- extern Ping_Pong_Buffer res_buff;& Z6 S7 N; ?3 G9 Z$ A2 t' p
. l. W' ~/ a8 y; o- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列. U+ e3 t) Q0 S5 `
- extern void k_linkQueue_release(linkQueue *queue);//释放链队列
5 u' d" R8 A3 h' q& R2 B - extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据
' e( a! ~& x; c - extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据8 A: z) L0 V7 Y7 j5 k
- ! H6 @- G" [# B4 F0 L
- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化0 }6 b) c- i6 P9 Y7 h% _7 V
- 3 q, q2 K% N' m" }
- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1% ?9 Z G8 K4 m2 o2 \6 h0 h# Z
- //设置主从设备号! }1 F2 f" F2 e V8 `1 Z
- #define PROTOCOL_MAJOR 1' y2 ?, ]; i+ g, |- |: Y
- #define PROTOCOL_MINOR 0 @" A4 b/ U6 p8 C# L/ T1 ]5 j
- 3 o( z% O0 e4 w. ~$ J* y
6 Q3 L: T0 l5 C: E% H4 F2 u- : ~2 I" [! n- S! b2 g5 e
- //定义设备驱动的名字或设备节点的名字
' w3 E& |# A* H# \. F5 s B - #define DEVICE_NAME "protocol_driver"
" {7 F6 S- C% N" z: _; W
' v2 e- P. m" W* V- + u/ `3 V# X" q
- //定义全局的循环队列作为数据缓冲区
K; c+ u7 A t, w' [ - k_linkQueue queue;5 K+ y- B1 }, }9 q
- 1 Z: U- E- G; @3 m& s
- //寄存器地址映射全局变量
0 [% S: q) Z o& R- F# ? - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器) i0 X1 P7 P, ^5 I! ?% s- \
- unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器
4 b$ @6 P$ y4 }& x" H - \3 n8 [2 }/ k, g! n
- //物理内存映射全局变量2 {, a1 Q, z9 {2 d
- volatile void *mem_base = NULL;. M( e$ x# ^0 f6 I
- volatile unsigned char *cur_buf_ptr = NULL;
& O2 C1 c% y3 u4 f - volatile unsigned char *data_ready_ptr = NULL;
* ^1 M6 N3 M6 o4 \: s' W - : ]5 f B: m) f
- & b7 U( B* G, K7 N. ], s2 f2 r* z
- 0 ?9 S$ O1 H& |# I& W
- //定义读数据等待队列头,IO阻塞* ]8 j! `' L1 l0 Z9 X |
- DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);) d6 n7 Q; z0 n9 v6 \7 T+ T# i
; V9 a- q, Q1 V- //定义原子变量: J& E5 ?% V" f: i+ Y
- static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备
2 g/ W$ T" J1 e8 i: D - 4 c* R! w2 g( N6 t' `2 V; O4 d6 P4 l
- : H' P# x& w& h: e4 z# h6 A
- //定义设备类0 B9 M- V) z2 L5 F$ v( d
- static struct class *protocol_class;* ?% f1 U9 T- K1 w
- struct cdev *protocol_cdev;
# w: c+ Q2 c; Y' } v - dev_t protocol_dev_no;
6 E0 q8 o$ Z! f; N. \3 ? [
- o( V0 A: M1 v. ]- /*定义tasklet和声明底半部函数并关联*/5 D8 v/ e) ?6 U+ }1 L, o; T
- void read_data_tasklet(unsigned long);
. V3 s0 f9 k* V# G2 r - ; G V! P8 p4 x) ~# j2 O+ X
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);. j, @* Q% k+ w' e# N% Q
- //将CHIPINT0_tasklet与read_data绑定,传入参数01 e7 v4 V1 ]2 B9 A
# B$ d8 ]. d& P4 O& Z9 k0 w- /*中断处理底半部, 拷贝内存*/( d3 p7 m0 u" l) u- m# H
- void read_data(unsigned long a)9 N3 m4 u* i# J6 u
- {
8 b1 T9 X% C7 C+ f8 a - if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1
! {" A/ w3 E1 a9 p$ d' K - {
6 _* [. Q, h2 d' \ - read_quest = 0;1 C, }& x1 a6 m+ a& `$ j
- wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
% c7 R q5 p, f - }$ U8 S7 ~6 S5 `1 \6 D
- 7 B% n4 r+ w" l( n0 ~
- }4 G U; ?6 y8 C+ n$ S
# p3 q' k% q. c. O# B5 p- /*中断处理顶半部*/4 s* W& j: g9 t9 j0 Z- H
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)% f- J: H2 T, u
- {
) n& {2 W) Z" n/ D+ z: y - //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
; I0 T( T8 q0 H ]7 W6 a. r( A - volatile Buffer_Type *next_read;
% l( ~' l0 R/ |3 i1 ~) {4 Y: V4 D3 C - //如果DSP数据已经ready
! l1 _9 l0 N1 t2 x - if(*(res_buff.cur_buffer->data_ready) == 1)
" f, L& F6 t$ y; ~0 m - {
: P' k& k# J- _8 p - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer
6 Z: M% A3 e1 } - {) m* a, ?+ n, m$ [
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer
$ l6 O% @2 R7 ^2 Q, ]8 }# | - //printk(KERN_ALERT"read ping\n");
n ?" M$ E9 k% c1 V! O - }' e1 k* N1 p/ m9 y& v
- else
- f7 u4 X( E: M! S9 w3 ? - {
+ @1 P. U3 m( F' n w; T - next_read = &res_buff.ping_buffer;//下一次中断读ping buffer
* b" x* L( ?9 P - //printk(KERN_ALERT"read pong\n");; m" A) o$ |2 x. T6 q% k
- }# b( L# s- |1 Z, J
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer/ V! K) j% R% b g- v7 ~' d1 a0 x
- //将数据插入链队列
2 {! K' u9 Q) d+ J# k! t5 A/ k, X# I; Q ] - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);& \! z( T. K- E0 L7 T7 d. _+ g
- //标识位都重置7 S, ^6 d) @ E) N
- *(res_buff.cur_buffer->data_ready) = 0;' C+ `$ p% r( V! ~
- *(res_buff.cur_buffer->data_size) = 0;- P' k# v6 ~" P9 ^7 ?7 e( e6 ]# J
- res_buff.cur_buffer = next_read;0 X. h1 p7 p" {) b, \
- }
" Q- {0 G/ v7 C8 g7 y - //清楚中断标识
8 d4 U* v7 y" A( F" b# m& Y4 y: h - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status
& P+ o3 ]" u( k! b - tasklet_schedule(&CHIPINT0_tasklet);//调度底半部
: ?. U4 T1 B) ^) _ - 7 D: m4 t; r) q+ t# Q
8 z5 F5 |; l" q: Y' Q" ?. v" ]5 `- return IRQ_HANDLED;
$ Q5 `0 A: Q8 `
/ i0 Z ?8 f' W% M% }6 @/ P8 J- }8 `; D; d' z0 T: E o
- ) B" n7 j- N' H% w u6 O
- //文件打开函数5 n0 N, U, e; s- _6 \& e
- static int protocol_open(struct inode *inode, struct file *file)2 m+ Y% `; i% @+ ^
- {
3 I- K9 F+ T5 R) V% G - int result = 0;) Q, j; {8 ?5 y% [
- if(!atomic_dec_and_test(&dev_available))
- e) y" m7 C# A0 G f2 ~1 V: o7 ~ - {5 O, |) b! S9 E. z4 e
- atomic_inc(&dev_available);
) i9 k3 i5 n% q: N - return -EBUSY;//设备已经被打开
- x/ @9 ]0 v1 Z3 Z - }% M- F( h, }5 f5 u- x
- printk (KERN_ALERT "\nprotrol driver open\n");7 b- r' m4 S# @7 n
- return 0;
0 Y% {1 I0 r( r; T - }
' h4 r+ S: D5 z' g1 j" i" l; @+ H3 ]- V - 4 |7 J/ ]* D) {
- //文件释放函数6 w- M, g+ p; e t! Z$ Z
- static int protocol_release(struct inode *inode, struct file *filp)
$ B5 `* j) ], h' x2 z% Y - {! `# m% L2 h+ e# j! C) Y) P% A! h
- atomic_inc(&dev_available);//释放设备,原子变量加1
0 O Y8 R- A) [% N" o4 w. K - printk (KERN_ALERT "device released\n");
" f/ n5 t5 L ]3 c) T5 m% L m6 ? - return 0;
z/ x1 {2 r! p" `; g5 ^/ U" G - }+ q4 A; D" {1 p2 X5 \! R5 U" L
8 m J/ p: |& ?% t( P4 ~- //文件读函数
0 z- v# h/ f" {$ p2 S$ t9 [# h - static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)
7 J | A8 J2 q+ @$ I* ^3 b; o - {
) k! l9 Q+ g+ H M* s9 j9 m3 p1 p- A - int ret = 0;
1 T* y( Z7 L" j0 S% c) c9 W - //定义等待队列; ~/ R, p9 j a
- DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列* u2 [+ {& ^' E! _# o) {6 I$ C
- add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
( d3 u' u' }8 W1 H$ R - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
4 j8 t8 b% o9 c: [" t - {5 V B) w. K7 C6 p- W3 W4 O4 @
- //printk(KERN_ALERT"\nbuffer no data\n");$ C- t7 j) v$ T# j n
- //如果是非阻塞方式读取,则直接跳出
! p( `- z( N+ y! H$ n# c - if(filp->f_flags & O_NONBLOCK)# s% ~+ V/ K1 a! `, D3 ?4 U
- {
+ B1 E0 H; I: B* L - ret = -EAGAIN;& E! L# y p7 i
- goto out;! V8 ^ G- ~6 D' I: a
- }
/ _9 r1 ]6 d* L5 R$ L U( G# e - //阻塞当前进程,放弃cpu资源# r" x. a" g8 b) K, O2 U9 ~
- read_quest = 1;# r3 g3 z, c/ X; I7 E- I/ ^
- __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠
; g8 k3 C! D1 W4 ~ - schedule();//调度其他进程运行
1 R a) B1 D1 V$ E; ~! `$ B: ` - if(signal_pending(current))# ` \; ]4 O; y" ` E7 r- s, m
- {
% g5 O7 P1 N8 A+ x6 U' k - //如果是因为信号被唤醒,则返回到系统调用之前的地方5 `6 E# |( \7 ? ] D4 ^) S+ W6 i
- ret = -ERESTARTSYS;& U) s$ ?5 u# `1 Q
- goto out;- O6 D* \* U i5 L8 z& K
- }* ]8 _4 h0 _& ` R
- }
7 V; i9 {! s4 @0 x - //将数据拷贝到用户空间) M, ]0 o2 S% J+ z0 ?, f6 }. ^
- ret = k_linkQueue_getData(&queue, dst);; s9 X% E+ p" Y7 [
- if(ret == 0)
/ Y x% T$ F6 { } - {
$ Z, d( C) w2 O3 N5 x/ Y1 a7 ~ - //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
6 m* o# K/ H, U1 t& y - }
7 F& B1 A; L4 r5 U# K7 t - out:& d$ r7 H& t; F* C9 t
- remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列- V" W" J: _3 t V Q) i/ Y7 `7 Z
- set_current_state(TASK_RUNNING);//设置当前进程为运行状态
' t: }$ A4 i" M+ k$ q - return ret;4 d" r' O9 q; O! S
- }, J0 P7 r$ [2 ` R3 Y) d
- ) q# m. v/ t# L0 c
7 q9 L( h2 \& s; E2 t5 Q- W- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)
1 P/ U/ `* C7 P% u - {- T' b' x, d& b- d
- return 0;2 d3 Z% S7 U+ i. ~
- }
' {9 {+ F% H# a$ Z& Z7 {" T D - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行. O/ ~( F+ Z# ]9 N/ D0 w! w: O
- open()、release()、ioctl()协同调用时被调用*/
6 ^; T5 l# p! @7 D6 x; k - static const struct file_operations protocol_fops =2 q! j. v* T J3 W# c3 c: g! A4 q
- {7 {* u$ h% f, b6 j
- .owner = THIS_MODULE,
2 d) b4 t" p3 P3 ^ - .open = protocol_open,9 j, s! g8 J- s8 \) L- z& H
- .release = protocol_release,0 y* h. [5 \7 z0 f' z# {. l
- .read = protocol_read,
" U2 }. f2 o+ A$ x - // .write = protocol_write,; |# R+ N- m4 M$ [% h
- .unlocked_ioctl=protocol_ioctl,
" W2 B. x* f$ |# x% s - };, O" {; V r1 U0 r5 k( u9 I% E
% f) Y3 U( s' t h/ ]! u% \/ ^% o- /*设备驱动模块加载函数*/% U3 }0 Q' O0 t0 ?2 Z* d+ k
- int __init protocol_init(void)
& k: S( Y' o. D" z - {. s9 W e* P0 Y T
- int ret = 0;4 u+ s- Y- K t6 {2 _
- int result = 0;# m+ R+ H+ d% \' t
- //申请注册设备号(动态)9 H) F, C% I3 ~3 G3 z
- ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); ' |5 Z- j m/ I2 b7 _ c* t
- if(ret < 0)
& Q: Y* F7 z( _: Y - {
+ p- w- o! {0 }+ L% j; | - printk(KERN_EMERG "alloc_chrdev_region failed\n");
0 P. [$ D }1 ^% }: {6 D - return 0;
4 R2 ?) N" @3 |' f) p - }
" z2 `: r% u& T& f$ }: B - //分配cdev
$ a5 F8 X, l: X - protocol_cdev = cdev_alloc();
^5 w, K0 N: h& D i - if(protocol_cdev == NULL)
! O" M# H# N; g - {# f$ R9 _1 n7 _: h+ G% F
- printk(KERN_EMERG "Cannot alloc cdev\n");
) ]4 X8 u9 C0 @6 C - return 0;
; F! n/ b0 w" m - }- ]6 ~2 K& N; z/ M/ `
- //初始化cdev0 Z& S4 e6 J8 ~4 S
- cdev_init(protocol_cdev,&protocol_fops);' v- H' y7 V/ x. H% R4 t( a
- protocol_cdev->owner=THIS_MODULE;
* ] I1 j" |6 A9 ^8 c o1 F - //注册cdev/ K! ^' f& y2 W N- m
- cdev_add(protocol_cdev, protocol_dev_no, 1);
4 W- D) \6 A; [/ o/ \ - //创建一个类: I* X$ o# P& V9 P9 ? T+ ?' q. H" p
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);2 W% \9 a( S+ ]. A
- //创建设备节点/ n2 s7 y9 f f! ^0 l* ^
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);9 a# P5 h- K9 ^
-
1 z+ i7 e. u3 T2 q/ b$ X- @ - " i1 V9 N7 |# T1 S0 i1 c
- //申请链式循环队列作为缓冲区DSP数据帧的缓冲区
1 K$ K+ v# T% ]) H8 V7 L - k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区" a3 A& y( G1 [2 i [" r
+ W; s \3 C( `$ s* O( A$ q- //映射ARM的核间通讯寄存器
* j; x2 o+ G8 V* F4 Y7 a* T - R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
7 J0 k2 T8 {; h: P- H - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);
0 u; e# r1 m2 Q* R( R - //将物理地址映射到内核空间
# ]; b G3 D) X! m - mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);
/ z6 C, \/ `" |8 l) p9 H& C% u* j - //共享内存初始化! s- S7 U5 i3 V ?
- SHM_ARM_Init((unsigned char *)mem_base);+ v8 u5 f3 C) R3 A8 R
- /*申请中断*/8 s( P3 k/ Y! b
- 2 B; d3 J$ g' ~/ i0 P6 j
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);: L. n) }& z8 I5 a
- if(result != 0)0 _" e$ _1 e# `
- {
7 }" I& }9 y q1 p - if(result == -EINVAL)
2 D3 m8 M8 L9 G: D5 f - {5 E- u/ m) X& t1 e7 P: t4 V2 t' `
- printk(KERN_ALERT "irq request err:-EINVAL\n");
. w0 ^ v- { R) r5 v, {! L- ?& G: F - }' h5 S2 a1 Q9 I& r/ A; B) T
- else if(result == -EBUSY)
5 n8 F: @" I' b! ` }; m h+ T8 I: f - {
9 g1 [# A" a: }& K. g, y# v - printk(KERN_ALERT "irq request err:--EBUSY\n");& S* F g& z( j9 H2 u) q6 P: l
- }( p8 m( r7 r/ X+ E7 ^4 @+ J7 A. Z
- else+ c4 W5 o! V7 M1 F7 c8 K" I$ U
- {
2 {3 m( C( W. D0 V( F1 W - printk(KERN_ALERT "irq request err: unknown\n");
, E- n3 U0 W) i4 B - }" C. {/ L0 t6 U( [( ]7 O9 h; }
- return result;9 @7 [7 i) |5 Z4 b. x
- }
1 W6 L& y! g. o4 x: O! s - return 0;
/ O& Y0 G6 @ _; F: g! r8 x# z( h - }) k& s' L% h8 o+ }, w, A! p. g
% S8 y0 Z5 X. j: }2 ]8 X- /*设备驱动模块卸载函数*/
" W$ w, a6 z. R# J' H" l7 a' Q - void __exit protocol_exit(void)
3 e4 Z. v% j6 L+ y. v - {
- w& d! }* q! q5 J' ] - /*释放中断*/
* _; a$ V9 K G! s2 X% v - free_irq(IRQ_DA8XX_CHIPINT0, NULL);. T2 N/ Y7 |4 J
- //释放帧缓冲的内存% [( y. s2 \7 ]
- k_linkQueue_release(&queue);; d6 b, G% O1 _6 n# H+ m
- //释放寄存器映射
& t- n1 Q; a. E+ M) o. L0 l; d - iounmap(R_CHIPSIG);
2 h% ?! U" l4 H! I6 d C - iounmap(R_CHIPSIG_CLR);( J6 |8 e8 P* y- Q% {, B8 K9 Y" F
- cdev_del(protocol_cdev); //删除cdev" E9 ^! G: T2 z" M2 s* ?. E( P4 ]. F
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号
$ H; q7 `9 |% R' F: D3 X& ]3 I - device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
, e- e" Y4 d4 I% B7 d - class_destroy(protocol_class); //销毁设备类1 {! P! o/ r& s7 e$ N
- printk(KERN_ALERT "exit success\n");, ^- x; s6 y% M$ s( h; c: m2 }
3 V. b2 z& `3 l7 X5 O- }' G3 X" e$ X9 Q0 o
- //驱动其他部分省略
复制代码
4 }+ T# T" ]" [$ N5 T9 R# M! B L: P% ^4 ]
|