本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑
" h; L7 w/ g8 R+ h, F1 X3 R w) ]( k9 x: p9 v, m* R
项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略% @0 i4 Y+ Z* c$ m( b
- 9 A' e6 a! m9 S9 @+ S
- //引入其他模块函数和变量! _( {3 y, U; K0 [
- extern Ping_Pong_Buffer res_buff;- x+ }( `, Q; ~% q6 k
- ) l* O) L+ s: @4 _ T
- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列
1 E4 ^2 H3 H2 D' m, o7 y - extern void k_linkQueue_release(linkQueue *queue);//释放链队列5 J, w6 K4 o1 u7 N2 f q
- extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据
3 Z1 c8 R- c- ^. P- U( m7 v# \( E - extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据2 x2 x! @4 H/ O( _6 r0 @
# p M" L( ?/ [& \- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化# j5 J9 w2 w/ [8 \$ m% ~
- 1 y7 q* L; @# Z: ~0 m
- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1
/ P! ^/ f4 c6 D/ a* R - //设置主从设备号
6 c. a( v# V6 M( s' x9 F! ~$ n/ f - #define PROTOCOL_MAJOR 1
! V+ f4 p$ Y; R# Y4 s4 L' ]7 F, r - #define PROTOCOL_MINOR 0
2 S9 |1 L, |# P2 `* j& V
; p3 [. \& q/ n' M- N* p, \- # P6 k; c! h4 T
0 L* F" m; a7 m- //定义设备驱动的名字或设备节点的名字) L+ F* M7 e- b* _
- #define DEVICE_NAME "protocol_driver"/ U+ U9 P( J! s/ p
: ~0 _) }: v3 |- ! A2 p: \. d: U7 G% L/ w3 T! A
- //定义全局的循环队列作为数据缓冲区
, L4 ?+ `) o8 o* Z, [ P - k_linkQueue queue;$ ^3 a7 s& }8 c4 W; B
- 0 D6 W5 N3 b: ^$ X/ I5 j% a3 h
- //寄存器地址映射全局变量
: t( _' ]$ q7 O' h0 V - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器9 m# \9 U1 R; N) h; X0 d
- unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器. ?! M# J( g# x
- - P Z. u! N5 |7 F
- //物理内存映射全局变量
& d' f' O) d; P o w9 N5 _" \ - volatile void *mem_base = NULL;
7 _" f$ E# V" o' C% e - volatile unsigned char *cur_buf_ptr = NULL;" Z5 W {- T4 ^" Y& B
- volatile unsigned char *data_ready_ptr = NULL;# H# a9 h* p- W9 ?* _- \
- & s9 {1 b! H; g/ x; G
7 G5 X1 a# x o- z0 i& V. f- 8 L4 s5 L7 r' a2 n
- //定义读数据等待队列头,IO阻塞1 K: N" S1 s; B! k8 k/ z
- DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);
1 p& V* y n9 V' }
. P1 d7 ]# S( R3 Y- //定义原子变量% ?; s4 i( w8 f9 k! p9 T- d
- static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备$ O) ~! m2 Y7 j! \! ]7 y& V. s
- 1 L! r* q4 e0 O) p9 H9 C4 w$ o; W
! E" V, Z8 y5 _" o# j- //定义设备类% J! L4 d& W' Y& r. j O3 O
- static struct class *protocol_class; Y6 {& J1 k0 w% {( h; c
- struct cdev *protocol_cdev;
% W \2 v7 t8 {0 |# r8 L2 `, b - dev_t protocol_dev_no;
4 I2 h; V u2 d! W
% U( q# {8 U, N& z2 J- /*定义tasklet和声明底半部函数并关联*/8 C5 E) A6 l$ }4 J
- void read_data_tasklet(unsigned long);
7 I+ S) j! T' {2 Z! p% r
" K8 `, X9 O" l% ^- |5 Q5 o- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
0 X& w0 I9 x, \ - //将CHIPINT0_tasklet与read_data绑定,传入参数0. [ A1 F: E/ N' T: t H
: A) b% R5 v* A- /*中断处理底半部, 拷贝内存*/, k' m d+ Z1 C
- void read_data(unsigned long a)* J4 g8 i6 i0 n! r9 N5 {6 U
- {
6 c9 g$ B+ U4 r5 _ - if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1" _" {, [% h9 A0 }
- {
3 W' ^! A% H& o% p - read_quest = 0;
; I( f2 [0 Z# q5 l; Q" D - wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
& \) ?8 I/ p9 P4 O. l* E - }
9 B8 D$ M; S- P
% ?8 w- K* g% ]9 z- a" M! [ S- } t/ `/ A7 h! O; c* ~( Z: I
- 7 b- C$ d: e, D. w) N( H
- /*中断处理顶半部*/
8 s% n5 O' K9 K7 r# v - irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)
1 |8 n0 D, o1 q1 W, q4 q- o0 |* o - {8 `1 |; z$ \/ t: t
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样, t' f2 z2 k: a( w* Z
- volatile Buffer_Type *next_read;
1 v; _1 t4 m$ O8 K - //如果DSP数据已经ready. k4 ^% A/ Y( U3 r
- if(*(res_buff.cur_buffer->data_ready) == 1)5 [$ S* w% L& Z0 G8 o
- {
9 T4 I# N. P$ e - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer4 g6 N) s+ z! l
- {
. t/ W) ^; x! E, f8 U2 X$ g - next_read = &res_buff.pong_buffer;//下一次中断读pong buffer4 R1 B1 q7 l {- O/ L3 K5 K
- //printk(KERN_ALERT"read ping\n");
0 E+ y' V p, j2 B; Y/ ?" B - }& v. E* b) S V1 Q; m4 g3 A
- else3 l$ z- v% r5 B( e
- {
; c ]3 w; E5 c6 k! c - next_read = &res_buff.ping_buffer;//下一次中断读ping buffer
% t5 V- U! z% N - //printk(KERN_ALERT"read pong\n");* o! A! X9 C# ]% X- x+ [
- }. J+ H7 H, M' ~( L# r" y
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer
8 _/ k* Y5 E8 h. d( E - //将数据插入链队列
f; b9 B/ u4 E1 j$ v - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);/ o Z4 A# F/ q- j' Z
- //标识位都重置; \; n9 ~& }: Y3 h8 j
- *(res_buff.cur_buffer->data_ready) = 0;
. Z& A) Y: s" M, r, l - *(res_buff.cur_buffer->data_size) = 0;
/ N9 i5 o+ r% W4 g - res_buff.cur_buffer = next_read;. @4 l- P3 }* H0 K* G9 D4 ?4 Y/ ~5 `! A
- }
9 M% ]# v$ `3 D7 ^5 C5 a - //清楚中断标识$ ~6 ~4 L- w7 M8 \/ M5 L
- *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status
, M+ d# A7 [+ F. A: h3 ? - tasklet_schedule(&CHIPINT0_tasklet);//调度底半部
( K" L0 K; B- ^. }, ^, t
8 p `- h; F" a" ` A0 [( q
7 O; ]7 C9 {* J$ p8 B" o- return IRQ_HANDLED;
+ E$ V9 w$ Q# j
' D, K! ^# @9 b$ G9 C' h4 |3 ]- }
2 J% ~3 }1 D3 y1 f' q2 b; N
& X, Y2 j- u* D1 D X$ x- //文件打开函数# ]. B- i3 Q! L
- static int protocol_open(struct inode *inode, struct file *file)* P9 G9 x9 E7 _
- {
9 \, W/ ?; Z* C8 d( I$ K$ a, B! O* D - int result = 0;! z! [0 ~/ q1 u9 ^" {, Y
- if(!atomic_dec_and_test(&dev_available))5 ~4 f U9 k4 w$ \8 r9 U
- {5 _& |" k T- r9 D0 M/ M! ?1 N$ i
- atomic_inc(&dev_available);
4 N- h# S6 I' e% t* E: B: U0 ^( _ - return -EBUSY;//设备已经被打开
" K1 y8 J v8 E* E; X! r8 M9 m - }
* ^( r8 `$ X# y6 W# Z0 k# ]' q# g - printk (KERN_ALERT "\nprotrol driver open\n");
% \4 r3 w7 f) Q3 E% O - return 0;) V' m4 w. ~# E
- }8 D% ~+ p3 J3 X; S/ C" I
- 2 \) {, K8 `0 v" f1 } X
- //文件释放函数
/ e9 r: U0 C* O# k! P - static int protocol_release(struct inode *inode, struct file *filp)
8 c/ u6 B6 v6 j) X' `2 x - {- r l* ^: D' P5 o7 H2 N
- atomic_inc(&dev_available);//释放设备,原子变量加1. U7 Q! S `+ E5 }, ~; Z3 G# ?# p, |) m
- printk (KERN_ALERT "device released\n");
* ^* D+ Y/ H* ? - return 0;# A& _2 }5 R- m; `
- }0 f: Q0 J* c3 s T6 g& a
- 3 Y. T$ |/ g- w: j) E; ]: F
- //文件读函数
: |- \" j8 \$ `% i - static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)
/ O1 x7 v! [+ z; ?" x6 K" T( B - {
7 {1 z9 T9 q& P& r ]- @ - int ret = 0;
" \* N! f% y7 g5 t1 { }8 D - //定义等待队列
- s9 T: L/ p5 I. {) O/ g - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列# |( Y" a: v& y, Y# S
- add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列$ K" n8 d4 h- U# k+ o& Y
- if(queue.remainNumber == queue.blockNumber)//当前buffer没数据 }$ o3 o$ v j2 E
- {
% k" ?; O& |& r, J: w/ U - //printk(KERN_ALERT"\nbuffer no data\n");( ?& z' R) {8 c5 F$ P
- //如果是非阻塞方式读取,则直接跳出
6 j( c. [$ G0 U k - if(filp->f_flags & O_NONBLOCK)
! ~1 h* j, i6 j) D; e1 G* {0 P - {9 O/ ~0 d8 b+ r9 Y/ G+ U5 h
- ret = -EAGAIN;
/ W {+ t" ^7 S c - goto out;
1 S5 ]! @/ T) V6 a0 Z/ l! X - }* h( @6 K: G/ ~+ M L4 {, [
- //阻塞当前进程,放弃cpu资源3 b; m, m8 e& ^6 S
- read_quest = 1;. c9 k- N8 B* [1 p
- __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠) O% Z3 E. k8 {5 {9 y3 h! M8 B0 I
- schedule();//调度其他进程运行/ t" P; ~; h C: t
- if(signal_pending(current))+ b" z, t; `9 T# `4 ^
- {
. Q5 L: |8 P: m9 C - //如果是因为信号被唤醒,则返回到系统调用之前的地方
4 x8 Y8 R) ?5 q& S" V5 |* J' T - ret = -ERESTARTSYS;
$ M! v1 \0 a) t - goto out;; f1 e7 Z: f6 ]) m! [) d- b
- }
( v. \1 k( C& ?$ A - }
4 s7 M6 u5 C3 {( d# D# T3 H - //将数据拷贝到用户空间
" Q/ S- T6 v6 ?# K5 Z4 D: g - ret = k_linkQueue_getData(&queue, dst);
! L5 M! u6 G2 G4 Y2 ^- F( O4 E6 ?) \ - if(ret == 0)! n. {3 ~; m! _7 u8 d) p
- {& R! L g; ?7 P S. s+ y! P! h. R
- //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);) \6 D' B1 \# z+ @% E" B- k! Q
- }
9 G1 F# ~* d3 u. M6 a6 K4 L - out:
8 w5 S! N0 w9 G+ X - remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列
7 ?9 A1 R, b! [( }7 o - set_current_state(TASK_RUNNING);//设置当前进程为运行状态. o; H3 c9 L1 s/ R' j& d
- return ret;
# t8 ]- i; ]8 C+ l, j! e - }, i4 g3 n9 } t, N& m
- ' S6 V4 Z' N4 S/ c
# w, T: C: e0 ^& r# g' q- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)
0 l( Y. I- ?, k# a9 N - {
2 J9 R6 F) |0 ?+ H: v/ m - return 0;
' g, k0 v+ o7 U- a7 Z1 f - }
/ @5 i6 E$ ?; s" O& J. E - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行
( R. t+ e4 @5 F. Y+ \$ T - open()、release()、ioctl()协同调用时被调用*/
6 |0 s) r+ w6 u$ j2 e - static const struct file_operations protocol_fops =
1 t% y; g6 Z; y3 J; Y - {
1 R, t" f, N- |9 R - .owner = THIS_MODULE,
. O- ]6 o$ a! Q% X6 p0 s3 I - .open = protocol_open,; Y1 `/ j r+ I: r/ s3 T; s
- .release = protocol_release,' }& {8 b' T( D. ^" I, u
- .read = protocol_read,
2 s' j+ g% _" P- h- t, Z3 Y O - // .write = protocol_write,- I9 T/ L' ^- a% h9 s. I2 h
- .unlocked_ioctl=protocol_ioctl,) F8 f+ q: U, D8 t. i
- };5 |8 Z! N3 S% ~
8 s2 V# J8 H# W- p- /*设备驱动模块加载函数*/
# ~: o/ y: ~2 j! r$ M) N$ l, O; M - int __init protocol_init(void)# F4 K" R" T2 K6 }
- {
9 J# G' O5 B5 c6 x - int ret = 0;
+ T0 s% ?" x _; Y. j! _ - int result = 0;
7 A5 {% R, D* d - //申请注册设备号(动态)
, v9 Z2 y+ l6 D7 T - ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); 5 M+ m, X- @1 h4 O0 o; r/ h
- if(ret < 0)
% Z# u7 v* [- z. \2 K - {8 J. ^! a* R T
- printk(KERN_EMERG "alloc_chrdev_region failed\n");+ N0 h$ f8 j# j* v# o2 |8 \
- return 0;
$ L7 B2 S3 }( p9 A/ K' R# |7 F) z - }
. |6 q) B& K% `( V+ k - //分配cdev! c! f/ L* z o0 V; E. ~3 ~
- protocol_cdev = cdev_alloc();
: g$ D! l! X! w- P& i - if(protocol_cdev == NULL)3 q/ \! N4 ~$ U6 }$ c3 E# o
- {) M/ B2 N, L8 V' C+ D
- printk(KERN_EMERG "Cannot alloc cdev\n");
7 g. e R- f) E+ u2 k - return 0;9 ]- _% W# r% F5 u5 U; |3 [/ ]% V/ {
- }# T3 m, |& o; }( }5 c
- //初始化cdev
4 o) S8 s$ k0 t6 W! U - cdev_init(protocol_cdev,&protocol_fops);
- i! Q6 K- ~, L8 Q, d - protocol_cdev->owner=THIS_MODULE;
/ K- a3 W: s& Q; d+ Y0 p - //注册cdev; C) N$ q& d E
- cdev_add(protocol_cdev, protocol_dev_no, 1);
8 l9 B9 n5 Y) w/ v - //创建一个类' J3 ]" Y9 R0 D/ y3 _
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);/ j0 m; T9 q/ ?8 v# i; a
- //创建设备节点& @, w7 I4 u% ^5 Y
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);
8 O: Z1 `8 @" B# h5 Z8 p -
' ^6 \7 a: O1 R s0 r l6 j -
. r1 ?: I: a- w$ V' |! Z( s0 F$ ^ - //申请链式循环队列作为缓冲区DSP数据帧的缓冲区! L% J n4 H9 l* r
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区
; S& \. I4 f3 d' d$ g7 \, L( F7 ]
% f! V5 _0 J8 X9 L& b* \7 V- //映射ARM的核间通讯寄存器
, I" a6 {# `; |3 _ - R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);: O/ X- @6 I# c ~8 Q
- R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);5 ~; d1 _& V9 }; t3 C
- //将物理地址映射到内核空间* Y) N8 k, k% Z5 F' y a
- mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);6 u, }4 a( @; ?; O7 j3 @
- //共享内存初始化4 ^6 V2 Q1 i; e/ l# c; H9 |! ^4 I8 w
- SHM_ARM_Init((unsigned char *)mem_base);
: N) Y+ e9 y5 k, |) E+ i - /*申请中断*/
& @) j0 S0 N/ H* t - + a- h% c& |3 \6 @' g' Z) @; q) C
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);) V+ s7 @1 B2 ]; p/ |& c9 d
- if(result != 0)# ]' e6 ]6 d5 ?6 F6 x
- {: h3 A2 z+ H1 ]# J7 Z
- if(result == -EINVAL)
3 j# C" d* _9 K# e/ N- w - {- ]- k: g5 m! c% c+ Y" g8 \
- printk(KERN_ALERT "irq request err:-EINVAL\n");
+ C/ U1 [* b. v+ c" c: r- N - }* z. n. t. ?! G8 t' t0 {
- else if(result == -EBUSY)3 G! y( X: f% j( ?* G
- {
2 F. I$ ~" ?. a1 p& P0 y5 m - printk(KERN_ALERT "irq request err:--EBUSY\n");
# @, J% C |$ I - }2 v. i; m0 e! x" O0 N D3 z D* B
- else: V E6 D7 [" ~/ |5 \: i/ T
- {
# |" E* v9 z0 z5 @6 }: Z. i( X - printk(KERN_ALERT "irq request err: unknown\n");
+ G, ^' o) c7 S! s3 @ - }% P3 s# O$ s6 p! T4 b8 |9 h# n4 q2 R
- return result;8 K8 c+ h6 X1 a* g* m! i
- }$ C; g! D- B0 g: `3 j* a
- return 0;3 r! K2 x. B4 q* o% ?6 i* E% E
- }6 |- c5 B! [+ }# {' H2 `% z
; l! X/ e: r9 c" A5 F# }- /*设备驱动模块卸载函数*/) A5 W R9 C& c
- void __exit protocol_exit(void); x* ~/ h( i* r
- {
+ J1 `3 E6 ?. s6 r - /*释放中断*/0 b2 D) l6 u: h3 X; Y# R/ J" ^
- free_irq(IRQ_DA8XX_CHIPINT0, NULL);9 O: ^% T( f- ^4 }0 [
- //释放帧缓冲的内存4 w2 ^; H L5 j7 ]1 ?+ a
- k_linkQueue_release(&queue);
0 k( R3 g# N8 e' Q - //释放寄存器映射2 n# x5 w' G: A0 c$ f }0 p
- iounmap(R_CHIPSIG);
* Z" b# X, r4 D1 U: y* T$ A - iounmap(R_CHIPSIG_CLR);8 K, [) x% I$ f# M
- cdev_del(protocol_cdev); //删除cdev" [# z5 V5 k5 R8 l- {9 \0 l5 T4 M
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号0 W" J7 o/ P1 v& U
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
& J2 D H1 N2 w. @: |$ _8 b - class_destroy(protocol_class); //销毁设备类8 M; `6 S: ?* y4 P# H/ V+ m: Q# k
- printk(KERN_ALERT "exit success\n");6 e, _0 g( l3 n7 N) v) n0 r
& q$ U/ o$ X; c% r' P3 ~- G: j- }( W9 {7 q+ c1 X4 |( p! g
- //驱动其他部分省略
复制代码 0 f. u$ f8 y8 B4 g% a
3 \+ z. \' ^) F! h5 X ]- Y8 O8 P |