本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑
! r; ]) Y' x: }( w& _, n0 p+ v# z0 K8 M$ m' p: d7 h1 }
项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略
E. ]; K- i" l$ N' v- F
% C9 b( }4 @* r- K7 K- //引入其他模块函数和变量
. R! X. ~( b, H; a+ Q3 I2 i* a8 c1 _ - extern Ping_Pong_Buffer res_buff;
2 y' \% J; q& Q0 ^ - + B* s' e! D- A/ |: {, I- b
- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列
* k% {( S' \/ e% ~" a6 E - extern void k_linkQueue_release(linkQueue *queue);//释放链队列6 I' o: X* ^8 B6 @% ?# {) n# W
- extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据! e7 r3 }. H7 f/ u/ q# K9 m+ o
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据
. L! \/ z5 O# Y2 v( I9 @
; }2 B9 u& e [- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化
7 h- ~" P- y1 B; Y8 ^' x
3 z, v' o5 ]% V& S. H6 g- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1& A& |6 O9 W. j0 {
- //设置主从设备号6 d; m$ y- h, R2 [; [& [% v
- #define PROTOCOL_MAJOR 1
6 M% r2 ^9 ?( H - #define PROTOCOL_MINOR 0
9 o! Y+ |* A& J1 b3 _* P+ m
: u) _) @" [7 V) M8 X8 H1 }
~1 f$ u$ j+ @2 P) @: k+ r4 Y/ R
' N7 D% u' X% r8 z- //定义设备驱动的名字或设备节点的名字4 i8 y2 B. o8 Z& z1 I) e3 Q+ |
- #define DEVICE_NAME "protocol_driver"9 g% {+ y; h' N7 Z
- 5 A* K/ H, h( T: `' m9 [
' Y) o7 P1 n# e. x1 t- //定义全局的循环队列作为数据缓冲区
q! Y, r0 K0 ~8 f) I - k_linkQueue queue;
& @' y$ U+ @: N: U) a' O& @/ `
. R1 p5 _; T/ P5 X8 x6 l& x/ N1 } {$ B- //寄存器地址映射全局变量
5 H9 L7 a. x N5 ]- P) X y - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器 _! F7 S; f8 G$ O) U' P8 |8 y( r% ?
- unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器
& u" ?8 G, x) m2 S+ S) S3 s - 5 O0 L" D" @4 j
- //物理内存映射全局变量, A5 H& p- s7 \: a& Z! h
- volatile void *mem_base = NULL;
8 L& k- Z2 ^. p: S' ?2 r - volatile unsigned char *cur_buf_ptr = NULL;
2 o. d! ~' h. i - volatile unsigned char *data_ready_ptr = NULL;& @5 x, P4 k7 x
+ B" }5 L% N w& z; A- 4 X7 {, U/ E6 [3 b7 k4 J
4 H" _) T5 Y1 T- ~- //定义读数据等待队列头,IO阻塞
4 z5 v% Z4 J9 x5 B/ s - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);
$ c4 E( A, _3 Z - 2 H/ J: y; L/ ^& G8 @, R6 L
- //定义原子变量5 V# l1 z/ ?* ]: g" C: i) x
- static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备; j3 v2 H" W' J- b
- 0 x/ m, F) J' y8 P! G6 O
- % F) ]) G/ {: M, j1 D
- //定义设备类9 R( `( ?- r4 Y3 f: d
- static struct class *protocol_class;
/ Z0 T' V( c0 k0 V: O( G - struct cdev *protocol_cdev;4 h4 t- G0 M5 A
- dev_t protocol_dev_no;
6 X# G8 J2 U; G/ @7 y+ V. m2 h - , |* j6 T1 J5 x2 q
- /*定义tasklet和声明底半部函数并关联*/
( b6 X k, T0 b6 B - void read_data_tasklet(unsigned long);- F g, q- i' P
~+ V Y* I3 v! @& k7 ]$ E0 O- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
- U! s D" D) i& d" k. g9 D - //将CHIPINT0_tasklet与read_data绑定,传入参数00 G$ ^$ L# [0 S: e
- 3 L' i" R2 d: _! q
- /*中断处理底半部, 拷贝内存*/5 n8 g4 J8 g! f/ Q! Y
- void read_data(unsigned long a)! Y% r+ r4 e! Q9 R5 C
- {' {! U! F5 I' B5 ^0 C% A. ]
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1' c Z( I, r! T8 n3 q* ~! ]7 i
- {0 Y, |- u5 y5 p8 S
- read_quest = 0;
; h( J; U/ P1 F I% E6 x/ l5 U - wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
& U% d% L0 m6 x- M - }
7 J: \; M) \5 O$ g - 2 S5 x4 f- r4 J2 S, R
- }
2 A8 g) m4 {" n) |: d0 [
; T$ o0 o. r! ^! ? x) |- /*中断处理顶半部*/8 G2 s0 X, l( W
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id); r6 j$ B4 p8 e, Z# f4 {- m
- {- Z" G6 w+ h% A' r
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样5 m* V3 t6 f# M( _6 M" Z! V, E) r; J
- volatile Buffer_Type *next_read;
% |' }. o. ^2 P" I6 o - //如果DSP数据已经ready
; e4 n% F# G0 X ~$ D9 w5 {5 ? - if(*(res_buff.cur_buffer->data_ready) == 1)
; o- H# ?. o- C6 R' g A; ~ - {0 v9 i" E2 L5 @5 J! U
- if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer: [1 L Q2 c- r7 F+ v
- {
+ w% |$ N4 g5 X7 N. m6 r- A7 m - next_read = &res_buff.pong_buffer;//下一次中断读pong buffer3 s/ v3 ?. |1 T8 r- x" _
- //printk(KERN_ALERT"read ping\n");
& O, t. @; f4 @& }3 F" G - }
0 {# L: [+ q% U. f8 Q3 n Z | - else4 M) k5 I' O, p
- {3 K* u, F, r% H9 E4 j- m
- next_read = &res_buff.ping_buffer;//下一次中断读ping buffer; ~6 k, C! D5 T9 J- g f) ^( p
- //printk(KERN_ALERT"read pong\n");/ \0 n1 y( U0 Y2 S" ?. T/ n' c9 u
- }) Y9 v- a) \8 X1 x/ _
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer
3 s3 f: p" o V5 p4 L0 l9 i8 } - //将数据插入链队列
* x- e ^" l; \: ]" t3 Y - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);$ ]* h, J a; R& M
- //标识位都重置
# g. t3 @. z4 Y$ z& I$ d5 O2 i9 R - *(res_buff.cur_buffer->data_ready) = 0;7 O z4 p! K) i. b$ C; @
- *(res_buff.cur_buffer->data_size) = 0;$ y& Q. T0 K. m1 ^! ]. d
- res_buff.cur_buffer = next_read;7 l+ D3 X7 h1 m4 X2 M
- }
p7 A( m+ [/ p - //清楚中断标识/ d2 G. w5 |" g3 ?% F7 ]
- *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status4 P# C) R i5 v- Y6 e- [) D
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部
?7 I$ z% R$ @3 r - " G& p# J. h" P8 M4 m2 ]
- 8 Q. G0 y/ N0 Z4 ^3 F
- return IRQ_HANDLED;
. d& S3 {5 y: |0 |
" b; y3 o, G% T" [0 n0 V- |- }
" D8 q9 H: s/ _" s; h
9 @$ b- W& t" o- b, A- //文件打开函数/ v% |+ T( R9 G! I& Z
- static int protocol_open(struct inode *inode, struct file *file)
& r2 n" s2 Q' e2 q3 ~( o, c- Z3 s - {% {9 A4 |# H4 V' j/ T6 e
- int result = 0;
* b4 s* S" o& [( `- Q. [ - if(!atomic_dec_and_test(&dev_available))
: C7 ?; N! q1 M* O& L$ k - {
0 `1 E5 p+ j! b - atomic_inc(&dev_available);
( [& N$ K: E3 N7 H" M! b - return -EBUSY;//设备已经被打开 n0 ?; P% o& V: T$ u i
- }! ]$ Z; ~$ K1 |- _$ U
- printk (KERN_ALERT "\nprotrol driver open\n");
2 t7 ~7 F+ ~$ Z2 C" d - return 0;2 D0 u6 A- y6 x1 s" ]" \
- }
( i) p1 F3 [) |( D0 b1 s
' ~ Y4 e+ i5 ?, |/ X- //文件释放函数) c" D( q6 V3 l' N% A& k
- static int protocol_release(struct inode *inode, struct file *filp)1 L/ } |' n6 S) K2 o/ v# K2 s
- {! p$ N; i \5 x% n
- atomic_inc(&dev_available);//释放设备,原子变量加1# ~+ `9 k2 z7 Q; ~
- printk (KERN_ALERT "device released\n");
( @6 ?- t, W0 H$ R. [& n' q2 C - return 0;& \( n/ r9 R* D# P6 P; O) |. J
- }9 l5 `, i3 w; y! ? j9 e6 w* ]7 \
( x+ }: S* @. m1 j0 `- //文件读函数. F! C% F1 V* c5 A4 ?$ p1 o/ S0 _
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)/ t, y Z6 ]' [& e$ y1 f/ w
- {( y6 z* S. z1 u' i. {8 R
- int ret = 0;
+ t! w! K7 s+ ?; m7 T - //定义等待队列6 L$ l$ Q( t: L, W7 [
- DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列
0 w' `: ~6 b- R6 T5 N4 n - add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
* @3 x8 [# ?' `0 @2 F- i+ h' z - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
4 b; b* y. }% X3 e- O - {
8 S8 H0 l2 H F) ?3 f4 { - //printk(KERN_ALERT"\nbuffer no data\n");
! N5 \+ ]/ |; P+ k, w2 Z# W - //如果是非阻塞方式读取,则直接跳出
?. M8 q8 u3 m( w% \$ l - if(filp->f_flags & O_NONBLOCK)
! P* Z& C" L. p7 ^# H! p - {, I$ M1 J$ H( A
- ret = -EAGAIN;
+ i9 W+ p8 p" _: p - goto out;* t0 [+ R, m# M9 z- _2 {: V
- }* y1 r9 n/ d* a3 i- V+ I1 v) K6 P3 @
- //阻塞当前进程,放弃cpu资源
/ S/ M0 C) }. b. p* O& ^, E. W - read_quest = 1;
2 } X0 |5 r* b! T% [ - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠
. q0 u) u! v2 b - schedule();//调度其他进程运行
2 y: o' {( i& h9 N4 b# x - if(signal_pending(current))) d9 j8 [7 B+ T" q, a9 e$ r) {
- {% v; h+ W' o; ~( T9 q& S
- //如果是因为信号被唤醒,则返回到系统调用之前的地方
) L+ W2 i& j" u b3 w) @ - ret = -ERESTARTSYS;: Y- p; s2 J0 ^6 n7 X- c$ ^( v
- goto out;
5 J& m/ g! ?0 r: `, t. W0 L - }! c `$ {* U- k* l
- }: h1 x4 e0 D/ l! E% ]/ f1 P
- //将数据拷贝到用户空间
3 _. W5 S! C* A, }0 X* ~ - ret = k_linkQueue_getData(&queue, dst);1 ?3 g5 t0 O1 f' E2 B p
- if(ret == 0)
, P" S) _1 F# D4 N% H) `# S8 V3 d# R - {% ^! {) n2 c. v4 N' `
- //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
* W/ G( X* x) P/ C2 W - }
( w; e/ t/ `( Y$ l - out:) k7 Z* ~; V. f4 I+ e% b' n9 `* `
- remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列
1 H3 y1 R% q3 V: z; }" n& J. ~ - set_current_state(TASK_RUNNING);//设置当前进程为运行状态- F7 a$ S5 c6 M {7 X
- return ret;
1 n: c& z! c6 T$ z - }
/ B2 b; Z) d, [% A
5 ~& T- @7 D. V; V1 y3 G0 Z m- ! ]3 ?* F( b9 x1 P! _- K4 v m
- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)
0 L- t- F! y) E% O - {+ K' Q. d1 u" y9 |! _
- return 0;
V! ]: O% s* a - }
3 Y0 J) D3 ~, q% }# A$ e/ I5 L1 J - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行
' M$ W! C& U8 l U! S - open()、release()、ioctl()协同调用时被调用*/3 ^0 Q/ j1 F) H) S& t! T$ c
- static const struct file_operations protocol_fops =
3 O5 {4 B6 v# \% t% K" D& D - {* @0 r5 v( j3 ^1 w' d
- .owner = THIS_MODULE,
4 I' }2 Q* t3 W% h. k! l) S - .open = protocol_open,! L6 j; Y3 ~: n9 J( U) {* e
- .release = protocol_release," ]4 B3 ~7 F1 X/ Y: c: {
- .read = protocol_read,4 Z* j2 F, N$ A! t3 o. J. P
- // .write = protocol_write, Q% \& J/ j$ T: G
- .unlocked_ioctl=protocol_ioctl,
- ]: w: ]+ @+ Z4 i! Q w% y7 f1 X+ | - };
( \2 ^8 f x- d5 O) E
- s- P- p6 x, m( R# N2 h3 g- /*设备驱动模块加载函数*/* i! D$ u: p4 ~9 R7 L
- int __init protocol_init(void)
" c; k+ Q$ d3 ^% Q4 z: W% C# q - {
! V* ?- k5 J) q6 }) D% p - int ret = 0;7 }3 c# N" m. \/ u. p% b3 d
- int result = 0;2 q0 E' g$ s+ M2 p
- //申请注册设备号(动态)" K1 L( b# b' j( M% y
- ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); - |5 B8 Q7 W x8 j
- if(ret < 0)
5 Y( G7 w5 o) t* v - {
9 S6 d4 ^9 [0 [* G - printk(KERN_EMERG "alloc_chrdev_region failed\n");
]1 G3 j6 m+ Y9 l/ j - return 0;" l8 `- ?, ?- J* I
- }* C) c( m& h2 j" l( ]4 ^2 v8 _
- //分配cdev# V! ]$ m9 O8 u
- protocol_cdev = cdev_alloc();2 c" ?0 e7 ]7 p) K! w' }' b
- if(protocol_cdev == NULL)4 S. }' F3 W* _1 }
- {/ \6 ? g) H, {' I8 k5 S) y
- printk(KERN_EMERG "Cannot alloc cdev\n");
, @( ~( O& S3 s/ w3 k - return 0;* T+ j) m5 `( V# ]
- }
6 B% R5 U# Y+ V - //初始化cdev1 I1 l8 g& y3 L0 B. P
- cdev_init(protocol_cdev,&protocol_fops);% v: Z0 x: S8 d0 Z' d
- protocol_cdev->owner=THIS_MODULE;9 I8 |9 T8 N' E4 V
- //注册cdev% ^2 ~# e+ }5 U+ h! l7 i4 ~1 |& K
- cdev_add(protocol_cdev, protocol_dev_no, 1); 5 M E: o1 p3 d: J* e
- //创建一个类
' \6 K6 Y; e0 o8 O1 J' \ - protocol_class = class_create(THIS_MODULE, DEVICE_NAME);
/ [4 U, G f8 j9 @0 u7 Z+ } - //创建设备节点. w7 ^2 F6 k7 a5 C) s* H( F8 J
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);
$ c- N) J% Q1 a% B I -
6 F2 e+ q: M) P# g* u" c: ` -
5 W0 X; ]6 h6 s0 }/ P) d7 ? - //申请链式循环队列作为缓冲区DSP数据帧的缓冲区
; r3 ^9 B; r- |# j0 l, L) H0 @ - k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区3 s4 |8 V4 C4 @6 H
7 } j( \/ P1 X" M5 B3 M- //映射ARM的核间通讯寄存器* {3 c) d$ O! N; g/ p* Z
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
! D/ u) L; g m% \ - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);' F7 N" q. H+ U0 r
- //将物理地址映射到内核空间
) ?9 o* a. u0 {' k - mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);* H! S: u6 ~2 e1 l: K
- //共享内存初始化6 u1 r6 Y, I( M( @& }# R
- SHM_ARM_Init((unsigned char *)mem_base);
o4 s: P0 G! K' j' g4 w - /*申请中断*/
# e7 M T. {1 L$ O# E* h# d - ! l A6 |/ L7 O0 B) n; _6 e& `' |
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);" n5 s( Y2 o: c" l
- if(result != 0)4 V) Q) N3 d, W/ ^
- {
, e; f( s! {4 d5 u: T& p - if(result == -EINVAL)3 Z8 b* M9 y0 F9 H+ B1 O1 L
- {
$ K' Z0 L5 ?! o8 n- M L3 ] - printk(KERN_ALERT "irq request err:-EINVAL\n");
1 T7 Y8 Y4 @+ g" t4 J- f - }' S' I( H3 P# a4 ?
- else if(result == -EBUSY)
! \6 l0 J2 `; h5 b - { |, z) w! y. B8 R6 n j
- printk(KERN_ALERT "irq request err:--EBUSY\n");
U1 w7 R& D4 U - }& R3 ^4 V% B, V
- else
, p! c( }9 h$ c, [$ G0 s6 | I - {
9 C: {+ P' m) z7 E$ F - printk(KERN_ALERT "irq request err: unknown\n");
5 ]) l( N. p: T; \3 d& ` - }
N0 M" d6 v( e/ t, f( j - return result;. D2 j3 ?1 c2 e e
- }3 i# E# G. X2 w
- return 0;
3 w6 k$ u$ `& w" F3 L; j0 ~! H9 a - }( ~% W# u) t- p+ X. R) S6 ^
- U1 n- d ]1 H; v5 Q2 w- /*设备驱动模块卸载函数*/9 T9 I$ r6 r2 T! H7 G) C! t: {
- void __exit protocol_exit(void)
( R9 Z0 L3 L% N- p - {: E+ H0 f$ Q6 ] T+ V# V
- /*释放中断*/
$ E; G1 c) m" g2 f* E - free_irq(IRQ_DA8XX_CHIPINT0, NULL);' R/ K5 z' i7 x# H% @2 y
- //释放帧缓冲的内存3 v$ Y4 V+ L E: j
- k_linkQueue_release(&queue);# L0 U8 J# L0 ]2 W9 @! j
- //释放寄存器映射
6 ^6 O3 p) T% J* j - iounmap(R_CHIPSIG);% H0 ?. @0 ^7 [ l
- iounmap(R_CHIPSIG_CLR);
' w5 D* P% _3 A9 K" O1 o3 W% v - cdev_del(protocol_cdev); //删除cdev
! [$ e7 D' z8 ]; I4 J- j5 M8 r - unregister_chrdev_region(protocol_dev_no, 1); //注销设备号
1 _5 l6 l2 {- y+ R \ - device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
" h; _, G1 ?8 G. L: [* V - class_destroy(protocol_class); //销毁设备类
& \, A2 \1 O+ n6 ]' `6 a8 B0 m* D - printk(KERN_ALERT "exit success\n");
2 t; p% f H Y, F' z
7 r( T5 { w3 D9 D1 H4 z) O- }
7 ], u6 Z/ j% s1 ]" Y, ` - //驱动其他部分省略
复制代码
+ E( m+ @' [/ u0 p0 ]
8 N6 J- W- ?# R |