本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑 4 i$ \3 q" ^' [3 A, X0 c, h6 F
4 ~7 I$ C9 N! L% B3 g# ^0 x! n
项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略
) X0 P: Z5 C$ F: z' y - - S: T. z! s2 X; \/ X9 Z% }
- //引入其他模块函数和变量0 ]9 _1 e2 _8 S; e+ j
- extern Ping_Pong_Buffer res_buff;
) v* H) ?' u0 [. y+ Q
- @, Z* \& y- e- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列
" l3 T5 F1 w5 b) b ~; z - extern void k_linkQueue_release(linkQueue *queue);//释放链队列
7 f/ x2 `* e! |# ?' C' E - extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据9 M1 `5 v1 t, D/ x9 M) n
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据# g- T, {) y8 `, u0 s
- 6 X# a6 [: j; C3 y
- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化
+ h `: {7 V: J - ' r/ I8 \4 l) T- f
- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1: N U: e( K% N
- //设置主从设备号7 Y B9 L2 T# I
- #define PROTOCOL_MAJOR 1* a* ?& j* t w( o1 T* q, v
- #define PROTOCOL_MINOR 0) ^2 `) x. e2 c1 X/ n r3 E
$ g1 b+ r$ f( `5 c- : J( T- n$ m, O3 ~
- * D6 g5 V9 T0 _. `( G
- //定义设备驱动的名字或设备节点的名字3 n, ^2 x6 F, X* B0 E
- #define DEVICE_NAME "protocol_driver"
5 d# I; P6 a. Q& s
% w0 ~: s& r7 B
& t7 L3 _0 r! ^$ U- //定义全局的循环队列作为数据缓冲区
+ l# b) {0 i8 \/ J; y7 }: [ - k_linkQueue queue;
' _' x0 g1 ]) [5 P( ]& v: J - 2 ^* y7 [7 I b0 O% ]! s- t
- //寄存器地址映射全局变量: c: E$ ?0 j+ V' Z9 d, n
- unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器
: ^; j( [" a$ Q' L ? - unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器0 v7 D- F/ m5 H" m9 {
) j T1 Q. }: n5 k- //物理内存映射全局变量5 a- F& |. b" x$ r; C
- volatile void *mem_base = NULL;+ H; w6 A+ w8 Y9 x
- volatile unsigned char *cur_buf_ptr = NULL;
5 L. I! Y& J8 Z! i8 o. p, W - volatile unsigned char *data_ready_ptr = NULL; x0 \, n$ p5 X' ^6 l/ L
; d3 ?1 D9 N- S3 S" b, ?. F$ Z
0 ~% k. s3 P$ P# {( W4 m
3 S9 R* ?4 [* D2 s) T- //定义读数据等待队列头,IO阻塞
3 d4 F8 ^( H& n/ G6 p4 C% v - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);
c R" f* V" a+ ?% p7 K1 _# g0 s; y - : o7 j+ O, L0 U
- //定义原子变量* l; }; z7 Z3 c9 K8 d
- static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备' W3 C2 y9 K4 u# [; [& @6 B
- / @4 ~2 C. s! ^) ~7 u! b8 Q
( A$ Z) o! Q2 b( ]- //定义设备类1 v |8 X) B j
- static struct class *protocol_class;, L8 |2 c4 |4 F& |. B. p3 ^
- struct cdev *protocol_cdev;
/ c) j" I; i3 f$ c' o/ Z' n - dev_t protocol_dev_no;" O# a" e! T3 }6 k
- ! ]- r' D$ E p$ m$ Q3 c$ o
- /*定义tasklet和声明底半部函数并关联*/
0 |$ |2 m6 V R+ N! I) x - void read_data_tasklet(unsigned long);2 s! f4 |/ b- @
: ~8 h1 w# h/ ]# |% `- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);; D( t! C! H6 [ a
- //将CHIPINT0_tasklet与read_data绑定,传入参数0
0 A% I2 r8 }) L& ]: J: M - ' E6 T/ u- p6 M( r" \
- /*中断处理底半部, 拷贝内存*/$ Z+ Z, r! }3 L- R1 G
- void read_data(unsigned long a)8 M- B t |0 e
- {
* x- t$ [( E! U7 j - if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1
, x X3 i( U2 h4 J7 O6 w; W6 s - {5 l5 W/ h- `/ N( } _2 x7 K/ }
- read_quest = 0;0 q( ~7 a- M" ~6 P7 Z+ B# h8 `
- wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
6 u$ Q m. M/ [8 _# { - }
% ~- [6 ?0 T) h! R5 q! O
0 Q0 j2 ^! r' }6 R- }
, e0 T( j+ j5 d! S' B. j- K9 f - 0 V) N5 X ? f0 |, I% G" A6 L
- /*中断处理顶半部*/
! R ?2 @. P5 J, _ - irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)4 W$ R, s0 t+ l# z- X
- {
8 A, y) p* P5 l X - //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
, ^2 N M6 u2 g1 d4 u% N l - volatile Buffer_Type *next_read;
, I% s; o, l0 T- J! } - //如果DSP数据已经ready, r0 g6 z1 a, n
- if(*(res_buff.cur_buffer->data_ready) == 1)
( `$ A6 Q6 ?0 ? - {3 o& {( g! I/ A, f
- if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer% _) |/ {5 G& Q& \# v) I
- {. s" D/ E% L! U3 @
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer, u* G! B% Y, H- G* R- @
- //printk(KERN_ALERT"read ping\n");: H4 y' n9 |" r
- }9 E7 e# u' [# v, b4 c
- else
0 x6 v) H: H/ N - {
* q9 a- A" k" r* X7 U" C" W - next_read = &res_buff.ping_buffer;//下一次中断读ping buffer2 C9 L) C9 U4 } b$ d0 L
- //printk(KERN_ALERT"read pong\n");& r8 y/ Y5 `& I4 P0 [
- }6 Y' y* c Y. s2 u6 Z
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer* w( N6 k* l( u7 T3 |* q# H
- //将数据插入链队列
" G" ^: P2 f2 \5 y - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);5 g/ R0 Z! F2 j- @6 e4 w
- //标识位都重置$ L% M- P( A$ k8 u" M: w# W; m
- *(res_buff.cur_buffer->data_ready) = 0;% _1 P) T: Y9 A# a
- *(res_buff.cur_buffer->data_size) = 0;
T- Q6 A' @* T# K1 } - res_buff.cur_buffer = next_read;9 t( f: T; T/ r- S
- }, Z( p% i! t/ A1 ]$ r# e
- //清楚中断标识
* k5 N: s6 h+ C z& R! v! K" o - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status# P' E: V; b. z/ a& `4 p
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部 u: r+ w( I/ V; ~: w5 i
8 `5 P2 k4 `0 e
6 R4 e& {9 _+ @: v2 G- l- return IRQ_HANDLED;
1 t5 I- ]# H" b# q4 W6 s
: J/ H2 K2 f" K& d" e- }
$ b$ e7 P3 c( F3 x0 N
% r! b* H: e+ C0 S+ T' n, H- //文件打开函数
) l+ M! M& V3 C7 r, R - static int protocol_open(struct inode *inode, struct file *file)
" `: J& U- Y3 ~, y7 ?' r9 o - {
+ G9 H+ g6 t# e4 @' g6 z& Y - int result = 0;
+ M$ i, t4 ^8 d6 T - if(!atomic_dec_and_test(&dev_available))
/ v* D6 v. q: g6 c% i/ s- l - {
5 Y# y; w7 d& {" C - atomic_inc(&dev_available);9 W+ |# u' h$ C9 A1 {
- return -EBUSY;//设备已经被打开+ _- y3 A# x$ |# Z5 }* k, |7 l
- }
. T* y# U9 \2 T# t - printk (KERN_ALERT "\nprotrol driver open\n");; O1 B4 t! Y: l7 v* t$ A0 W
- return 0;3 @% x" \1 H. J5 r
- }4 w* \8 ^: s5 V Q" F0 @( n! {5 S
" e6 v9 L2 x+ b' Z+ ~: k- //文件释放函数
7 B6 H; b- _, ` - static int protocol_release(struct inode *inode, struct file *filp)
5 M8 d$ g2 `3 G6 ` - { a0 @& h5 F2 O$ P7 z
- atomic_inc(&dev_available);//释放设备,原子变量加10 y. \7 c: p5 v
- printk (KERN_ALERT "device released\n");$ F; ^6 N9 o& ? i
- return 0;! E, q1 X; U3 W5 ^1 B
- }
" J' A. a# u6 Z9 O; S! P9 X) r - ) B2 J. L* S6 z9 D
- //文件读函数+ @) n& S0 g- p2 {/ n4 U
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)
Z" S5 q* _3 t0 N0 m - {' d6 P+ t$ z- I& F% J, k, u3 F
- int ret = 0;6 |9 k! P) T r' l. F% y: u+ v* \
- //定义等待队列
9 G+ L' d/ b) B7 q8 |' n/ M/ x - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列
5 j' {, z% B3 m2 m3 e3 P3 z - add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
0 `( T/ K' X+ l+ O# o( Y5 H - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据9 g& m9 d" Z8 Z4 R- m4 G2 M, H
- {& ?2 }) X! }& ?- N8 I. E' W
- //printk(KERN_ALERT"\nbuffer no data\n");: _# ~/ X( X; ~; {3 h6 W3 T$ H6 ~
- //如果是非阻塞方式读取,则直接跳出
1 D# G' Y+ T- y5 Q& R - if(filp->f_flags & O_NONBLOCK) G) U8 v8 L% |8 H" x
- {
. x& L$ s9 A8 P3 ~1 B* u3 \8 k4 l - ret = -EAGAIN;
9 f Z0 \& M9 H7 v- J7 [+ ~/ ~. w, D - goto out;
3 i. S* v+ n/ ?& D2 n* G2 V* N - }8 m& A T# @2 Q K2 Q2 j# t
- //阻塞当前进程,放弃cpu资源' Q; Y1 a# \& ?$ J
- read_quest = 1;1 D6 C, b" r% v* K! |, d. n1 s: Q6 C
- __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠
" a7 L& N2 M0 C% b( J. f - schedule();//调度其他进程运行
5 T/ C) i0 p3 u( I$ l) \% S2 M9 Q7 H - if(signal_pending(current)). Q2 k2 W6 G. f4 |. t' H
- {) w' Y3 i- b2 ^ R& O0 X1 E
- //如果是因为信号被唤醒,则返回到系统调用之前的地方
) K, C7 }$ f) J) C) p' L2 _7 u5 C5 J$ ` - ret = -ERESTARTSYS;
* z: } P' z: C8 c- h7 j - goto out;- o x, M+ @) ?& ]' u/ u v* g" v. f
- } o( `; E( w: @
- }
, J* q) \4 C/ ^6 u- ~! n; f5 j - //将数据拷贝到用户空间7 {' k9 h% _3 K0 ]; `
- ret = k_linkQueue_getData(&queue, dst);
: W- i$ A4 }2 [) N5 ~& G - if(ret == 0)' l7 H: P& | S* s( d
- {
7 Z! Z, Q' ^- Z7 ? - //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
9 ^0 t1 }1 I$ M, `6 U0 N - }
n6 Q" {0 w7 M) h - out:
1 l; }$ `, v, |1 h& L+ ] r" u; N - remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列
9 `; p# \- i& U* m - set_current_state(TASK_RUNNING);//设置当前进程为运行状态
# g8 Q& i# T1 U2 E1 L0 U, A2 I - return ret;# G' X$ ~) Y% b. q! U2 H
- }7 ^0 @: r0 E3 S' }- o+ C1 c6 A7 e' {
- - C' N6 n9 a9 j, X; F" r% o" k
- . l) R: }, h7 S$ E6 Z3 |
- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)- H: O7 G# s+ S/ [
- {
+ D9 c& q6 K& _% E - return 0;
% Z" b. [- l8 ~" y$ R$ A - }6 V7 T% {! g0 j% o
- /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行3 P8 P$ D/ ^% } a) d* _. a; M4 _
- open()、release()、ioctl()协同调用时被调用*/
. e+ \' P. Z U( T, m - static const struct file_operations protocol_fops =
" \3 h$ x( l2 a - {
" _5 z; c& C& X3 h4 f7 H - .owner = THIS_MODULE,
& y) E. h* o" m, V% i7 l - .open = protocol_open,
& w# q ]1 C5 O$ D( P" x - .release = protocol_release, E) p# c, W( K+ N }) f' t
- .read = protocol_read,
/ G2 z! y: N1 O( u - // .write = protocol_write,
$ V, i! ~! _0 u5 J, G' u2 H8 ^( H: c! p* X - .unlocked_ioctl=protocol_ioctl,
2 i6 z( Y0 N7 E: R3 S0 l - }; x- f4 i7 {+ @3 ~, q
3 O! A5 _, q7 d Z- /*设备驱动模块加载函数*/2 N. |7 L' w5 b6 h
- int __init protocol_init(void)8 x2 L; k8 e. Y8 l' S" M% N
- {, \* V, B0 d) J+ R- _/ ]
- int ret = 0;
! S" U- C9 {/ R# G$ S8 [2 s - int result = 0;3 @+ A2 V* `/ G" O( {
- //申请注册设备号(动态)- a9 T9 ?# P+ N- d
- ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME);
% g8 a0 w3 z. w* n0 z - if(ret < 0)
2 N7 `5 u2 y3 K - {
9 G9 [0 p, ?+ l - printk(KERN_EMERG "alloc_chrdev_region failed\n");" Y0 }. l7 Z( V- f7 J
- return 0;
) H- E% {' G8 h - }) e9 f+ j. l( e& V
- //分配cdev# s( `0 V+ c: H
- protocol_cdev = cdev_alloc();2 _! Q- x6 b5 Q
- if(protocol_cdev == NULL)
* s1 W7 W3 O* Q3 o - {# m4 x( v% S3 @+ `2 a' O
- printk(KERN_EMERG "Cannot alloc cdev\n");: ^* M+ J3 m. ^5 ]
- return 0;
$ m2 R: J9 o; K7 M - }# t- m0 {1 W1 C$ D
- //初始化cdev% @4 {4 H: d) F' P
- cdev_init(protocol_cdev,&protocol_fops);( A* V$ d* e2 ]% R `, j/ E% O
- protocol_cdev->owner=THIS_MODULE;
" v3 s1 x& t8 N& A' A - //注册cdev
; p& \ y$ X Q - cdev_add(protocol_cdev, protocol_dev_no, 1);
5 _$ h) c. Q. u/ y+ D - //创建一个类! E( M% s5 v1 o4 \- _8 k# ?
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);+ t( P. o& L( J* X1 h
- //创建设备节点5 ?" u3 F. l/ p5 |9 V7 G% e
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);9 s' D4 f4 v' r
-
0 a5 K4 Q1 z4 S; D" | {& e4 Q8 w - , V5 o" x3 D: n- `$ u1 {
- //申请链式循环队列作为缓冲区DSP数据帧的缓冲区
. w8 n- [4 D5 F$ _+ g - k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区
3 w+ i9 Q% G5 J9 L7 x - ' s, `5 q' y( \: a7 o1 [- |
- //映射ARM的核间通讯寄存器
3 ?. Y0 j* j0 e* e# {1 h) p' u - R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);$ Z4 c: Q; a1 F6 Z/ k$ G/ k
- R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);
/ S. R& W- I4 G1 R7 \7 F" `' u& W - //将物理地址映射到内核空间# \/ ^" E0 q6 A( Q i2 _$ D
- mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);9 k* y) S( ] y" `- N" o6 o% K
- //共享内存初始化
- c; }" O& H& J5 x i' e+ x' f - SHM_ARM_Init((unsigned char *)mem_base);
1 ^' {: q/ N2 m L - /*申请中断*/
- b/ l0 X# ^1 x, g
! H9 A4 Q/ n- W/ d p- ~' d- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);; p! l. |$ ^- u5 b7 _" T
- if(result != 0)( l- ?" v. ~/ i# l. N$ \- |
- {
% _& `! o" _. f( m3 \! q5 A5 ] - if(result == -EINVAL)
' h" g* v' W" ?' p( t2 i! D# { - {
* ~6 N1 b2 T$ m# V( X - printk(KERN_ALERT "irq request err:-EINVAL\n");6 F( t* U3 A( P \* d
- }9 E& u; n: k. C$ |$ z) y1 X I3 W
- else if(result == -EBUSY)9 h: i2 n9 [5 R- d: }
- {8 A0 F% h4 |* Q0 e$ T: y
- printk(KERN_ALERT "irq request err:--EBUSY\n");
8 i, Z6 }: y( o+ w - }
. A g9 x: L$ r8 J - else) \2 u$ u4 Z$ x' i# a( l4 [
- {
: ^( c$ C6 K$ N- Y9 \, m - printk(KERN_ALERT "irq request err: unknown\n");% R8 f- k0 j% S3 k) |
- }
. ?' w. j+ q+ j# R: r& t5 g - return result;
* W: L# u9 y, i - }: \+ g6 A W! A) r, p( Y- Q" N
- return 0;: G5 e) z4 b* U& _( G/ e
- }1 ]+ p. P/ C- { ~* h j
/ v1 v3 ]) K, Q( u% N+ v, k- /*设备驱动模块卸载函数*/' G' S7 X$ {1 n7 I/ a
- void __exit protocol_exit(void)) h1 ]! U6 n$ e( ~
- {8 J, t% {# M3 r6 s( u0 G7 [
- /*释放中断*/
6 c0 {0 |; s: i+ G) \ - free_irq(IRQ_DA8XX_CHIPINT0, NULL);; I$ _* O5 Q& j
- //释放帧缓冲的内存
& J5 R! R! `4 x6 g! b) r2 @ - k_linkQueue_release(&queue);1 Y) T5 ~& L! w/ w6 A+ O! x5 s7 x
- //释放寄存器映射
+ o# j- }$ K* ^7 `$ h - iounmap(R_CHIPSIG);
4 d d& i. R1 y/ C/ Z - iounmap(R_CHIPSIG_CLR);
7 C2 M2 m* m/ O" F7 e6 N - cdev_del(protocol_cdev); //删除cdev
( V5 E0 k& {$ B0 o! O" g4 p0 }; g - unregister_chrdev_region(protocol_dev_no, 1); //注销设备号$ Q% h& l+ s6 t- Q
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点& |2 |6 R- N6 d( M2 K( h! r' L
- class_destroy(protocol_class); //销毁设备类
( x& b% A/ _% D* `5 f - printk(KERN_ALERT "exit success\n");
9 o8 C( |+ t* v3 j - 0 K3 S3 D$ P0 F( r
- }$ E) h% @0 O0 B3 B! w7 O
- //驱动其他部分省略
复制代码 ! @) E' i! ]5 x8 n, d3 `3 x
9 H# y$ U" z8 \: ^- v$ V |