本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑
k U7 r0 o4 K; ?& D) e+ R* M$ ~9 f1 Z3 o6 z5 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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略
# t* F3 j* R5 Q [1 e5 z - " }, j i Q6 [+ K P$ c6 d% z2 I/ G3 P2 M2 o
- //引入其他模块函数和变量
1 `+ s- K/ Z4 Q: O0 R, d - extern Ping_Pong_Buffer res_buff;
: q# g' p1 Q. z$ e( H# T5 j" ^
8 w# x8 A% U, W# A- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列# B' r9 u9 V5 [: x+ U
- extern void k_linkQueue_release(linkQueue *queue);//释放链队列
4 A6 h6 `- K) {; f3 { - extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据/ |; u& w4 S7 F
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据. F6 @* i5 r0 k/ r' [ `9 D
+ u h% I( j; W0 j- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化
4 v( J( a" q, \: e - ) ~! R* D( S. `" L7 E
- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1
8 U m- f8 f% }* _; s - //设置主从设备号
- ]& ?9 G- _. t" |3 N1 k: a. w Q9 Z/ t" t - #define PROTOCOL_MAJOR 11 g. ]. ?7 k, F/ c6 I
- #define PROTOCOL_MINOR 0
. G( b* }& g4 j9 I2 t7 }% A
9 k3 ~/ g# [+ ^8 u5 A( [- $ i; f7 z7 v3 i9 ]# i
- , ]7 E5 h& P9 T9 b# H z' V, B
- //定义设备驱动的名字或设备节点的名字
9 m# C8 I; d" h, {. j0 r. H, Q4 L - #define DEVICE_NAME "protocol_driver"
8 A: m- r- N) s - 9 N0 {0 q! Y$ \" s
- $ x# {' g/ A, q+ ]
- //定义全局的循环队列作为数据缓冲区
$ ~' N/ ^0 m% r - k_linkQueue queue;1 ?4 ~2 O5 [/ G7 x0 ?: o+ V; m' i
- Y$ T7 S" d4 `; ~- //寄存器地址映射全局变量
) T3 E/ h. P9 A - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器
$ M1 ^; L( Q- V0 O - unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器# H3 y+ _7 N2 a6 h2 Z5 U6 C% b
6 X6 I6 T% @. v) Y. W! f- //物理内存映射全局变量 d* i4 f8 K! Y. K# d5 j4 J# h+ v
- volatile void *mem_base = NULL;
& @/ i' G1 L2 Q - volatile unsigned char *cur_buf_ptr = NULL;
9 R) _+ B: ? u& E0 u - volatile unsigned char *data_ready_ptr = NULL;4 K* P: j& Z+ q0 Y
- e. Q( P: `( w- 8 M" A0 _( Q5 e' ] W; _. u& m
- u3 C) w" x0 C2 }1 A2 V7 o
- //定义读数据等待队列头,IO阻塞
7 {$ B- _; q7 A; z8 p e( d - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);
8 b* t2 H. Z% @$ a8 g, j4 h
- D, b5 P' e+ @. W- //定义原子变量8 C+ N. W! @$ V* S. ?* X; I9 X' ^; A
- static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备9 v8 q- g$ I) r/ G: J
- 7 Z3 E0 g5 D0 x/ o+ V F- e: G [
- " {+ F4 p, u5 g1 d( k M
- //定义设备类
t, b6 u4 F' r" h" X2 s) o& O - static struct class *protocol_class;
7 E6 @- D4 m6 z6 m' [# _2 {9 B - struct cdev *protocol_cdev;
+ q8 E& d# P5 ~* G$ T5 `( b - dev_t protocol_dev_no;
! U0 y" }! ]. q6 h7 }0 L6 a3 i$ r: O
; z" K s/ ~( V7 O) C; ~8 C- /*定义tasklet和声明底半部函数并关联*/
% @' _8 Z# }) ], P - void read_data_tasklet(unsigned long);
& k6 E# J: X" p
O, P5 }: Q( M1 k- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);: l1 L$ d d+ G+ b
- //将CHIPINT0_tasklet与read_data绑定,传入参数0
! ]5 i% d& x Q" I - 7 ~2 @% i4 t; h/ L1 Y5 Q) f1 m
- /*中断处理底半部, 拷贝内存*/
! z, @( ]% `5 X, k - void read_data(unsigned long a)
$ u# \, W! u+ L, w0 t - {; n0 {3 B2 G* W8 s n
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为18 X8 N7 U- Z) p5 s- L& Z3 I0 E
- {6 E l- ^' k8 h3 Z6 w9 H% @- v! A
- read_quest = 0;
* R* x9 I1 m+ v. j# G8 J - wake_up_interruptible(&wait_queue_head);//唤醒读等待队列/ W, v+ B5 b; H3 O7 w) z
- }8 Q2 U7 R9 Q" s3 }% V5 c7 u
- - d- B' @) s) V4 \8 X+ z
- }) r3 N3 _# _5 l& }/ v
- ) e) U6 |0 M+ o9 g: r
- /*中断处理顶半部*/6 m% k4 n8 Y6 l0 q! I5 Q
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)$ `0 U$ N3 ^9 v2 E0 N) b5 U; r8 E
- {, F6 E% c' Z8 L$ |5 u& c. W% x
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
) ?6 T( N) P: }! ^- C) p) p: t" b - volatile Buffer_Type *next_read;
) E, a6 z: U0 g6 M. z6 g - //如果DSP数据已经ready
! `' Q. F0 e1 w9 l - if(*(res_buff.cur_buffer->data_ready) == 1)
% k! C, B' X7 ~- N* A6 V2 J - {/ l- o6 b1 H( Z, z) P: s2 L2 K
- if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer
; r8 `$ F4 C) V v, I- B) p - {% @' _& N' G9 Z) b
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer( V8 q. C. @% ~, z
- //printk(KERN_ALERT"read ping\n");
f# F) X k' i, D" Q - }
9 J5 w) b. R& f4 w( f1 A - else, b% ~2 q$ G) b k, X' f! `
- {: q8 o# L8 b5 \; q$ L' N' q( [
- next_read = &res_buff.ping_buffer;//下一次中断读ping buffer
! F6 ]# c+ Q- s9 W$ {8 a0 e6 p) L* u - //printk(KERN_ALERT"read pong\n");
: w2 u' v# k6 N$ r* |9 [0 g( \: x - }* a' ^7 b) L1 n8 w
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer6 H" J% q1 `( s4 j# a
- //将数据插入链队列
4 V5 w& u6 K; p) R4 [ - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);8 b5 X6 k9 P2 I( w% \
- //标识位都重置' d3 D) c& e; y$ {1 J5 C* I
- *(res_buff.cur_buffer->data_ready) = 0;. T; t( G ]- U/ L! m
- *(res_buff.cur_buffer->data_size) = 0;
/ |6 q$ h* M/ z$ y$ @ - res_buff.cur_buffer = next_read;
- Q0 K: Z, Q) m% Q; @% r - } [6 ~7 l7 F6 I0 G6 ^5 B4 |& b
- //清楚中断标识6 g! @& C; H; h1 {0 U' V: x
- *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status# [' \8 Q4 u8 \1 h; f# Z4 j7 P
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部 ; @ n4 T Y( C. `/ M t
- , b g4 o3 L( f; I9 k* z
1 ` M7 I, U" D- return IRQ_HANDLED;
" O7 {4 G) n7 D6 I4 N" A. u9 P' y/ C - . N. P1 p* N$ z# ^
- }
% ~/ H6 Z T2 f: H0 U - ' u4 F# S" a8 D7 x
- //文件打开函数
2 n* G( B4 v( M8 W. ? - static int protocol_open(struct inode *inode, struct file *file)
% o; ]* M9 J' M1 s3 C - {/ b5 I4 Q) B* O6 s
- int result = 0;% O f1 }1 Z8 z. f. M
- if(!atomic_dec_and_test(&dev_available))7 J0 Y: C/ z6 r/ h; V; A& i. d
- {
+ I3 _4 L" G" g) l( j0 t' u) \ - atomic_inc(&dev_available);
! b3 o# B5 d) j+ n5 |9 a - return -EBUSY;//设备已经被打开# N# @, p% N# s; @, c V
- }
5 R2 o" `1 d5 k2 a& v; N3 e4 e - printk (KERN_ALERT "\nprotrol driver open\n");' h4 H5 Q$ ]# B$ |
- return 0;
( L* r# M) i# p* v4 @ - }0 W% ^) o1 y. O7 H: j0 w ]0 r( h" `+ p
) h4 l9 W7 F" x1 ?+ G. o- V! e5 F- //文件释放函数& |1 z8 E$ W( |0 h5 b4 l
- static int protocol_release(struct inode *inode, struct file *filp)
/ n" K) V, l* V - {
2 e3 c$ o! y! ~: ?6 I4 p3 |+ L - atomic_inc(&dev_available);//释放设备,原子变量加12 A+ ]! ?4 k5 C1 \5 x% F4 t
- printk (KERN_ALERT "device released\n");+ ^$ e& c4 _# T" K( {
- return 0;8 \7 D; k5 N, T! I+ o
- }
5 ?$ C" |. ` _+ j! Q+ V4 z; r - 4 W/ y- I% N- C/ D* c3 ~2 L, H
- //文件读函数. G" F, ^, }3 M! |- y) R
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)7 X: _+ E3 R) [, o
- {
; o% a T. |4 P! n: k - int ret = 0;) M9 I: v, f& k* r6 i
- //定义等待队列! K, Q$ k3 J0 a. I+ Q
- DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列
# w4 r( Z0 p& R3 M - add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列9 U, G# t8 C- W( j& n* Y/ \) L
- if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
8 X: S! w( |& {" g* U - {
3 `/ ^( I$ Z, m1 ^% A - //printk(KERN_ALERT"\nbuffer no data\n");
2 ?, V& c, U0 |( V2 ?5 v0 t - //如果是非阻塞方式读取,则直接跳出9 E/ k% b2 z( `& {8 H% o! G
- if(filp->f_flags & O_NONBLOCK)
+ g$ w: ]- X6 b - {
6 g# A$ D1 z2 M' B e9 V5 r( U - ret = -EAGAIN;
1 I7 w$ Y! G) ^ - goto out;
% X4 T1 j8 f q) q6 {& E; g2 y - }' t& _: I' k+ ?$ g% S
- //阻塞当前进程,放弃cpu资源1 X) d; p) }. S( }. v
- read_quest = 1;
2 A& N) d( e1 g# B3 _& a - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠
3 ^+ G$ C" y1 G. l0 H# | - schedule();//调度其他进程运行
8 a+ s! d0 ]( y, G; L - if(signal_pending(current))
: z' o" r0 p2 ]/ u, X - {5 `; Y; ?- A9 \3 E4 y- @
- //如果是因为信号被唤醒,则返回到系统调用之前的地方
, Y* ^' c( d: h3 D. G2 i - ret = -ERESTARTSYS;
! \3 T* s" L+ V$ M6 x* m - goto out;
& V0 C- Q) ~$ d) O! G - }* U/ d6 j# ?" |( R$ e' p- T; J6 \, U
- }
7 d: U1 ]8 ?) Z4 V - //将数据拷贝到用户空间
; d: L( y% O, j - ret = k_linkQueue_getData(&queue, dst);
+ r* \3 ]4 y' M; L5 m% d - if(ret == 0)1 F/ q8 L5 R9 `; @3 x8 b3 H$ H
- {8 y4 p/ ^6 t, K, S1 `% H! X
- //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);3 k( c5 } K$ x. u0 I0 {
- }
/ N# Z/ l* G7 ?5 {: p8 x2 P - out:
4 L( V# P% v2 B% B4 e - remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列, G' J: Q. h+ i. ?0 u: e/ F$ r
- set_current_state(TASK_RUNNING);//设置当前进程为运行状态, W# o+ a4 S% L" w
- return ret;
c# A, l ~% F0 w* ^ - }
6 P6 o% n+ i: w( n
: E6 [/ V% P; a+ y( c/ D- ) U5 _/ f, y3 E0 r
- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)/ C0 o% c% T; v0 a+ s4 i
- {* \4 r E" O9 C( J" `5 S
- return 0;' D) b6 E M# S0 @. M0 Q
- }
. Q" s0 N7 t5 g, E' B. X6 u( f - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行
+ L$ D5 I; x8 h6 Q! ?: O! P - open()、release()、ioctl()协同调用时被调用*/9 z% Z, k! c: [. }4 ?( K
- static const struct file_operations protocol_fops =: I* q( }9 G7 D( I. D+ A: }
- {; Q5 M2 a6 |0 }5 U& d" E) \5 J
- .owner = THIS_MODULE,2 q5 l6 W9 [2 F, U0 |, y
- .open = protocol_open,
& x" D+ Z' z y7 r - .release = protocol_release,* `8 q3 m. o4 ~" G: Z5 H, J
- .read = protocol_read, a7 b' ]1 `& ~+ [
- // .write = protocol_write,
8 }6 k! _- a5 b, G+ j - .unlocked_ioctl=protocol_ioctl,2 B$ r$ I9 c& h3 H# z: Q0 Z
- }; a: v7 R7 x+ U% q' }
8 q; t: r" s: Z: j7 }8 J; U- /*设备驱动模块加载函数*/
% k( k; B& z0 e4 X' G - int __init protocol_init(void)
2 M7 h- Q2 c4 x& g) T - {. p5 G; h2 y$ j% e
- int ret = 0;; n" z( p8 Y' S/ U
- int result = 0;
$ C' k: j: \, N- H - //申请注册设备号(动态) _1 {' E# ?7 i
- ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); ' J1 b4 N, }( A
- if(ret < 0)
* O7 Q- O8 v: j r d# _ - {8 J% y" D: n0 c- B
- printk(KERN_EMERG "alloc_chrdev_region failed\n");+ m8 R8 e1 t& ~' F8 y# u
- return 0;
( U. {" V" P/ f8 g) {4 K$ d - }! e2 B5 E3 O- A! Y- y3 o
- //分配cdev: `' V5 J# o6 s9 g& J6 p3 x: T
- protocol_cdev = cdev_alloc();; a3 G$ J+ f, P
- if(protocol_cdev == NULL)
* s8 D7 s6 e' ?( Q. @ - {# S: S# A) g- @9 V" J( a5 \
- printk(KERN_EMERG "Cannot alloc cdev\n");
8 c7 Z1 I/ \1 s5 e - return 0;& U3 h/ X: |+ D* _( y4 F! M @
- }
, ^5 f. u* B6 }5 H - //初始化cdev4 R4 G% D# Q K# z+ l/ B
- cdev_init(protocol_cdev,&protocol_fops);
# v4 e( @- |8 J+ P% o% T% ]& w3 K - protocol_cdev->owner=THIS_MODULE;
" W0 T+ \; J' A3 m% V( h - //注册cdev T5 ~! @" O! Q# E
- cdev_add(protocol_cdev, protocol_dev_no, 1); 6 T3 p- H# p' h' p
- //创建一个类
& V$ ^4 {# j2 p* A( s - protocol_class = class_create(THIS_MODULE, DEVICE_NAME);2 ]- k; @. b( f
- //创建设备节点
7 ^( D% X* s/ L0 l6 O2 m - device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);
0 H' n( p C5 M! m0 d$ O - 6 e* I0 B+ N A( O. r
- / Y$ C1 |5 z5 i: A \, b4 s4 L% C
- //申请链式循环队列作为缓冲区DSP数据帧的缓冲区
6 }' D E: ~5 p - k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区1 O, Y! Y7 m& Z% J9 D
- ( a2 j" B. i5 z/ V" Y0 J
- //映射ARM的核间通讯寄存器
' I, j( ^. D n4 h: v, `: T9 ?. L - R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);7 P9 N" @2 m' B: @7 t2 ~* R5 H3 g+ D
- R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);
; b+ m7 D) x) h! J - //将物理地址映射到内核空间
1 b0 q+ o% \% R( L2 s. R/ @# \ - mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);
9 X" ^3 A. a& d8 w- z8 S6 K- F7 t) Q: ~ - //共享内存初始化# M0 j% Y% H; }3 t% u- Z& M
- SHM_ARM_Init((unsigned char *)mem_base);
e. ~: j4 }& G0 e - /*申请中断*/, ^; u$ C: ?& b4 U" V+ v' r
; m# Q3 c8 i. C6 X- m- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);; o0 O3 N* Z* J) b) i
- if(result != 0)
5 H1 n! X+ ]& ^( q$ n# q - {5 |( B4 f3 m8 c4 z
- if(result == -EINVAL)6 ?9 o7 p% N) r( L
- {
8 ^# u% I" y: C+ s% n6 F; ^3 n3 o6 w) { - printk(KERN_ALERT "irq request err:-EINVAL\n");0 r* |$ }, l6 ~* e! K
- }9 h* o# S2 s) v
- else if(result == -EBUSY)
. w# }% F/ B' X/ I. g0 i - {% v/ b: U# l+ {/ x3 a& g5 k
- printk(KERN_ALERT "irq request err:--EBUSY\n");2 l2 N: M, n" F1 n+ ?
- }4 O1 R, G# |# ?7 q+ l
- else
' x9 P; Q% A9 P5 ]0 C) |1 { - {
* N6 V3 h" f- K- h+ H - printk(KERN_ALERT "irq request err: unknown\n");
" N& Y/ o: i5 r [$ F. ^' C - }2 m' ?4 e3 n* o, K. b" d! B
- return result;
2 @% Q8 f, ?, F a7 Y/ O - }& t1 H$ n( u1 J0 A. X6 O# r/ ]
- return 0;% e, j: _- O) G& k' O
- }
) ^% V! H3 f' C4 ^9 \) v2 z7 Y - + V$ }# w" F1 ]& z
- /*设备驱动模块卸载函数*/
( M; b& a- O* }! c4 q. Q - void __exit protocol_exit(void)
; C: m) H, g" J. s5 I - {1 U8 W4 h' Q+ m7 k% j# D. W0 J( c
- /*释放中断*/
2 T$ N7 D% q7 t6 f A# I& Y - free_irq(IRQ_DA8XX_CHIPINT0, NULL);' i. K& ]4 g& D7 w. i
- //释放帧缓冲的内存 f2 ^. @# J# g3 b
- k_linkQueue_release(&queue);: L4 B( f' ?6 j- [) L) I
- //释放寄存器映射5 {, p: r3 o1 u& N% ~1 D
- iounmap(R_CHIPSIG);
% c! J, ?4 G6 a# k3 s7 k5 n - iounmap(R_CHIPSIG_CLR);- c/ T% S c' ~4 s
- cdev_del(protocol_cdev); //删除cdev$ R0 {- B5 p2 B
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号
* J6 R! e6 {' A. ^8 a/ M, j - device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
( K, N. H+ X0 h) c - class_destroy(protocol_class); //销毁设备类% N7 s% s0 T5 q) T0 z& C9 Y( S
- printk(KERN_ALERT "exit success\n");7 {, f0 T8 |. \+ c4 C2 E8 A
* \0 q# {" a7 x' M2 z* o; @6 w- }
& M7 t4 f& }1 O3 ~ - //驱动其他部分省略
复制代码 - z& X7 T+ ]1 ?% _, t0 P" k
1 D# P/ u( M" A* g5 a
|