本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑
, A3 T5 W& f$ _' h! x G' w. r+ I7 Q( ]. o, Y& g* P
项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略 i; |$ |4 R$ C+ ?% R t* n
8 o* O C$ t8 }& B- //引入其他模块函数和变量6 U1 ~7 E1 [4 L3 e. p9 t
- extern Ping_Pong_Buffer res_buff;
! {# j0 }6 y% u: N# C# Z. u# e
8 x- z) R5 L [5 @- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列& B( V2 S$ H1 a: y6 I
- extern void k_linkQueue_release(linkQueue *queue);//释放链队列8 P y4 O2 m2 X# W* s; Z
- extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据
# T" V% Y; ?: y0 J' E - extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据# n7 c+ a8 Q V
. e, H: [+ I, j2 N- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化4 ], ]2 ~) p# b
+ C+ D- i7 J& f. e S- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置11 {& O4 E/ ]' m0 h
- //设置主从设备号- V* q. i; m$ s: r7 [4 `4 ?6 v
- #define PROTOCOL_MAJOR 1
) |- W4 J6 B8 k7 u$ b8 _ - #define PROTOCOL_MINOR 0
' R9 P: f6 {( D4 t. U6 p6 y& Q - + Y/ }0 M/ |2 M( s, R6 x E
- 5 T. x, S X4 X. s& o
$ U# k! d* S2 j& ?3 k1 Z- //定义设备驱动的名字或设备节点的名字' i+ r- C, L# V
- #define DEVICE_NAME "protocol_driver"
# {' S2 j% n$ e9 _7 `( {
/ q7 }( S$ r k0 E/ S& @$ P- ' v: j5 I* u0 z1 X
- //定义全局的循环队列作为数据缓冲区
9 ], }3 U( m7 R4 ~7 W) I, k - k_linkQueue queue;
* D! U2 s! t0 \+ g- m - }8 w; A' i' N& l, M; m
- //寄存器地址映射全局变量
7 S1 I( `1 ?7 R0 K - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器
$ l6 I) { p% f% L* s+ C9 p9 Q: ?* T - unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器1 P6 Z( x% p. h' x
% p3 [" e! J9 ?9 ^- //物理内存映射全局变量. E3 D' T( F4 {/ U" C
- volatile void *mem_base = NULL;- I4 R$ b1 x6 c
- volatile unsigned char *cur_buf_ptr = NULL;
8 |# h6 ^' z* _ - volatile unsigned char *data_ready_ptr = NULL;
* |, v7 E. D) c3 t: l* G9 l4 W, j2 T - 8 l3 H* Y" Y$ _) M" k
9 @9 q. K; z, H$ W/ i0 | |% W
8 d% w Y/ a h- //定义读数据等待队列头,IO阻塞
- ` \& s* P Z. u - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);
& y) N2 }: T+ |+ k0 h - 2 H' r9 a+ u6 e
- //定义原子变量
' T7 ^0 R6 c! N/ u - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备
% m. |6 W8 P0 A! u" R5 F/ G" ?: B - & `7 j- r2 d( y: D9 S
- u9 q6 S* ^1 C; w, w* e. U' L7 K- //定义设备类
% I& w2 t7 F4 P) ? n - static struct class *protocol_class;( T% A! l3 k: ^" |9 [
- struct cdev *protocol_cdev;3 ^1 g# `3 Z: B8 L6 s7 @8 e
- dev_t protocol_dev_no;
( \+ O5 y, }. ~+ q: g; c; Y& Q0 U - * H" j+ T: X% k0 ~$ f5 m" Q% @) {8 l
- /*定义tasklet和声明底半部函数并关联*/
0 c, m$ x4 M8 }2 ` - void read_data_tasklet(unsigned long);% j* b! m. f9 h! J8 o- ~1 ?
- ! E5 Q7 j E+ p1 h
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
& ^& v3 `8 I" ?4 w; S$ e - //将CHIPINT0_tasklet与read_data绑定,传入参数0
1 r7 P+ \. C5 b: l0 n( g; L - 2 Q% }1 g* K7 s9 m- N0 m6 i
- /*中断处理底半部, 拷贝内存*/
$ K* ?3 V- N& K; @ | - void read_data(unsigned long a)
6 N, B. m- T4 T& w+ w/ d - {; i5 K1 g$ Q) _9 t
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1
$ i3 r5 G& I/ l+ T - {. D3 p x; P# h; \, @* M: p
- read_quest = 0;
. d( _8 a# _3 J: E: e - wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
& b, }" b' h" r - }
% ~. r6 |8 x2 ~6 l0 U/ |5 I( `: ~
& e# Y% I m' {- }! G( S _' \ ~/ r X9 z( V E- }
3 P2 ~6 w7 Z% _; \% @) {/ K, x$ C- /*中断处理顶半部*/+ x; g* t1 C, B' w1 L: b4 K
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)
. b6 P7 D* l1 o$ k/ h; i - {+ A: ?" C6 S' b2 X( p, Q
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
+ [' \: @) U5 {3 o4 B I* W - volatile Buffer_Type *next_read;
3 A1 R: k9 z, v - //如果DSP数据已经ready
% u9 f7 _' g7 K4 v - if(*(res_buff.cur_buffer->data_ready) == 1)
; Z: Q) r! f3 p5 c7 l L, t - {: {: b6 h* E. B2 L% m6 C
- if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer; C+ |' i6 G S+ G- r' M
- {
9 \ P" h0 T( e( e7 B& G - next_read = &res_buff.pong_buffer;//下一次中断读pong buffer
3 X0 I- D3 b1 ~3 J( u - //printk(KERN_ALERT"read ping\n");
" s5 K# M$ |2 I+ |% U9 {, ` - }/ L+ C6 O7 U S' x4 c+ r
- else
! |( L7 m6 {9 c1 ~* W7 o6 R2 } - {" Y6 [% z4 G' C+ U) ?
- next_read = &res_buff.ping_buffer;//下一次中断读ping buffer
# ]* s: E4 E j- ^4 F+ z& c - //printk(KERN_ALERT"read pong\n");2 ]; q3 j g& b% s4 _9 ^
- }
$ T/ T0 Z% N" N# o3 M - *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer
; I; l0 Y% f! v, @1 Y$ O - //将数据插入链队列
! x* P2 Y ]1 P2 e7 X - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);
7 h4 T# r- _ P% v - //标识位都重置
" {) F( M% i* z. L0 a - *(res_buff.cur_buffer->data_ready) = 0;( t# K: M) o1 h' o
- *(res_buff.cur_buffer->data_size) = 0;
8 i9 O3 R3 T- v' H& g; Z - res_buff.cur_buffer = next_read;2 `; S' Z$ I) G. L; ~
- }
, |! a/ t. P! Z8 r, z& T1 S - //清楚中断标识
r$ s0 R! e1 D% Y - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status9 ?+ \7 t) Y6 m* ~) r: T
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部 $ f. v$ D+ x( Q: R
- ; a1 U* b- t9 g* c6 @, {7 J2 ? l
; f! _+ a5 K( _/ J- return IRQ_HANDLED;
, f2 W8 @' Z# O+ B/ Q' `; i9 s$ g
. l# ?; ^0 Y/ Q- } Y2 Q# a$ ? j; V! V1 `: m9 V
- # O+ N2 B9 T0 S) Y- n
- //文件打开函数
1 F0 i- L# o7 L# g$ x2 t: g - static int protocol_open(struct inode *inode, struct file *file)* ^& O+ N/ `3 q+ T
- {
4 }/ C' E* [1 c' q- P1 B. C/ | - int result = 0;* k! ^' g5 @, W( l) L6 i
- if(!atomic_dec_and_test(&dev_available))
' e; W, N" k* A2 |4 z, H - {. V7 H+ [* t+ A% C/ \. X5 R+ d
- atomic_inc(&dev_available);
" Z. v8 Y( A- O9 | - return -EBUSY;//设备已经被打开
. t; t, u; v; N0 r! z: P% U7 ~ - }1 y S- r" f( O- L: J2 I T5 J
- printk (KERN_ALERT "\nprotrol driver open\n");
0 I! p- h( e2 @. S* O4 V - return 0;. A) i* y, r: v
- }
+ j( m* l! |, ] - 7 y' d: C3 j- O n& u# f
- //文件释放函数
& K( s1 H- a) D6 |! J+ S6 C( I; q+ l - static int protocol_release(struct inode *inode, struct file *filp)! e2 ?4 x5 ?2 a% u, I I! f
- {6 h( \/ }& J; H8 G! N( J
- atomic_inc(&dev_available);//释放设备,原子变量加1
* X1 O5 I3 K- Z O' s; X - printk (KERN_ALERT "device released\n");7 w- i @4 d0 r9 v7 p) d
- return 0;
& A) C7 i+ s8 w$ @1 m# a: _! O - }
3 S8 r0 p/ t2 w' i0 \
) m+ m+ r& N0 [8 y7 n& B" P- //文件读函数/ B8 R# z. n) h6 m
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset) _# M" ~9 v, A v
- {
, `* S$ Z, q$ I6 u+ r# M6 V; s - int ret = 0;) q% y1 j8 f) H8 j
- //定义等待队列
; p8 y5 e* B3 U9 y$ i& j - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列# j* n7 Y" h3 i; W" l. J+ A. v
- add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
6 q1 I9 c& V% I# \: P5 h - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据' M) S7 D& C/ J9 p
- {
, b! l9 m% h. Y; U! s2 y8 S9 } - //printk(KERN_ALERT"\nbuffer no data\n");
7 j0 u* }2 P. @# m6 [( j - //如果是非阻塞方式读取,则直接跳出2 v) w5 N/ w, K7 l7 @' ]7 e, `
- if(filp->f_flags & O_NONBLOCK)
$ k( r4 m. E0 J. N: e - {
, o+ `( p9 N1 R1 m6 R" c; v2 c - ret = -EAGAIN;- V" d3 B- n' L% _7 i' r! K
- goto out;
8 B9 }. N5 J; f4 K - }
' l( C2 r0 m+ N. u% j - //阻塞当前进程,放弃cpu资源
2 c' P' L' R" L" H1 y h2 j - read_quest = 1;; i6 F# U6 ]1 x J! f
- __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠. ?! ]$ C# w& v, T' `! h
- schedule();//调度其他进程运行/ p& i8 W( R5 _
- if(signal_pending(current))% K* `2 i2 q2 u" H) t0 G& L) I
- {5 Q) N: K. k0 y! [/ Y! B, \
- //如果是因为信号被唤醒,则返回到系统调用之前的地方0 f5 N z! c% |% V
- ret = -ERESTARTSYS;) n" y3 Z" F8 Q' o! x; ^ _
- goto out; W" c# I- E/ S; Z- t8 }8 |
- }2 v$ M1 o6 F Y6 b, D
- }$ p' H5 S! ]2 l( X v
- //将数据拷贝到用户空间! y D; K# A1 W e. Q, |+ a
- ret = k_linkQueue_getData(&queue, dst);, x5 f5 F: Y/ N$ @4 i
- if(ret == 0)
: `4 m% _3 z0 b. w* z9 Q' c$ t - {
" u, E7 I- Z+ h; Y* O3 K) S - //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
) z7 |5 }* |. X( l# G: c - }% V8 l# w* b) }+ Q- \3 I9 V
- out:" ~# c( g1 O% C$ @' n
- remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列
+ z7 M9 g- V; K l+ v" r - set_current_state(TASK_RUNNING);//设置当前进程为运行状态
3 a) |2 X0 a. x! d7 H- L) J( _ - return ret;
v% { l# b4 y0 p - }4 u% ]6 E" i7 m3 y
: e9 \2 z( S+ F. ~! F* {/ r0 k/ b- : Z; K) z' q5 F/ W. t# w Q
- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value); @* _& S3 }0 M9 B7 W
- {
. M/ A, T% q7 Y, j$ ~ - return 0;
7 D/ M$ R4 p3 X9 U* [& t( [; k2 d - }
" g9 e) }( T# [# \: z$ c - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行
. Y, w4 T8 t& V - open()、release()、ioctl()协同调用时被调用*/
* m( O; b0 W+ [; R - static const struct file_operations protocol_fops =
% w( D3 k* M0 w! [# W. ^* W - {" k' [' w+ N) r8 z4 d
- .owner = THIS_MODULE,# e' m w. b4 t+ x* t
- .open = protocol_open,
* z$ m% ~9 E, o5 G. f - .release = protocol_release,
' U4 b6 {# x9 \7 H8 |- v - .read = protocol_read,
# R ~. f) T( B% u, m - // .write = protocol_write,* T1 f+ @4 u1 u0 A/ r: W, p
- .unlocked_ioctl=protocol_ioctl,
" c( K3 x" U" P6 u/ }$ u* q" Y - };2 X& k4 ?, B; e9 {- {2 y
- 3 ~8 D1 r! D5 t+ `% L2 x
- /*设备驱动模块加载函数*/9 G# O9 @0 c k. X5 S
- int __init protocol_init(void)
& u& L7 Q# H Y* v- a# \ - {5 y/ w, p5 J/ e" L0 t
- int ret = 0;
6 s H+ Q9 ^' ^" P( [' U - int result = 0;
# ?6 l: \; w- c& [% s - //申请注册设备号(动态)# ?; {% ~# p+ W4 }
- ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME);
0 o# m" P: n; V1 Q$ m - if(ret < 0)
+ o7 S, M. \! W! {* P$ I$ ?( u( Q3 r - {
% ^7 `& t# r* v9 S+ X, x, l# o - printk(KERN_EMERG "alloc_chrdev_region failed\n");/ `5 s7 m- f0 P
- return 0;
% A9 i; D/ s4 a3 t. X6 {9 f - }4 h2 e2 e8 s/ F5 G5 d
- //分配cdev
4 x: G) l6 G* J' E3 c D) u( B, n - protocol_cdev = cdev_alloc();2 g( V0 ~% C3 E8 R. i9 g( x
- if(protocol_cdev == NULL)
9 e+ [; x7 d; ?8 k - {
* d9 S) X* u' I1 g) X7 g& o2 J - printk(KERN_EMERG "Cannot alloc cdev\n");
9 e5 o1 j! x; n6 Y+ I - return 0;
9 P# D1 `6 p# l6 v, t% L* P - }
1 s- s e |/ y+ N4 K - //初始化cdev
) [# i3 v. X7 S& X8 W - cdev_init(protocol_cdev,&protocol_fops);
2 F: c& ^# B2 c+ z - protocol_cdev->owner=THIS_MODULE;, D( M& e. W b8 C3 x! C% P" L0 F1 L
- //注册cdev
* q' H1 \9 M1 v4 w J0 x - cdev_add(protocol_cdev, protocol_dev_no, 1);
( w6 \9 R) k# K - //创建一个类
/ C! n8 ~+ j3 H& g% q( j - protocol_class = class_create(THIS_MODULE, DEVICE_NAME);
1 J% H+ F, ^7 G; ~1 P7 K. z# x - //创建设备节点
' d- E0 ]7 V I6 X# R! |6 z5 A - device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);
& h4 d9 g& |. _# u6 ~ -
: ^; h+ G# f" j4 n" L -
/ [; m. [9 g1 R6 [. }. G - //申请链式循环队列作为缓冲区DSP数据帧的缓冲区: M" ?( y# L0 t$ I4 h0 L
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区8 N3 I' P6 d0 r" U6 Y8 f
- 2 p# A$ H m$ p% w
- //映射ARM的核间通讯寄存器7 x6 C; B" G+ b+ x
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
' ^$ C% X5 z) b2 i - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);
* o) m9 ]/ t3 @ O" P0 ^6 k$ `" ~ - //将物理地址映射到内核空间, y" u( {$ F0 w' {0 C( G- Z
- mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);
6 s. m9 u6 p4 j# k2 D - //共享内存初始化1 s6 n2 M& x4 _2 a# |4 [6 s
- SHM_ARM_Init((unsigned char *)mem_base);
- t4 w& r' c! A/ r. I V! [6 C$ x - /*申请中断*/& ~ y6 Q( w7 ^* T
- + ?- r' ]1 O" ^, |0 D
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);; K4 j+ |2 {1 y' k
- if(result != 0)7 v+ ]3 U& [/ J& [3 Q. }1 F) L& K
- {
9 U5 X; K9 ]+ X: G5 X" C - if(result == -EINVAL)3 U7 ?+ P! u, @- _$ ^8 U: e
- {7 ?( c7 \( a; q. p1 H# |
- printk(KERN_ALERT "irq request err:-EINVAL\n");
* W* [ ]" L/ }/ G/ z9 C" L3 v - }
7 ^& a: \- A( z/ E8 s5 T3 _+ J" X - else if(result == -EBUSY)3 ~$ Z$ n& u! Q5 c
- {
) \" K% b" G9 x - printk(KERN_ALERT "irq request err:--EBUSY\n");
4 }2 B+ L* Y ~0 p+ G# G - }
. ]6 T' L1 Z5 Z. G - else
) F* j1 k U$ [$ P; y; q; k$ I1 \ - {
0 J: d$ F0 w1 v) {$ p/ c2 d - printk(KERN_ALERT "irq request err: unknown\n");/ ?6 }2 z1 Y' [4 _) P1 E
- }. m5 }. @4 ]# g& \% x L4 W
- return result;
* C/ n" i- v+ Q# d- D* r7 m8 k* O - }
( @& ?' m5 {/ k - return 0;
% g# e5 m, Z4 f# Y - }
* w# y+ O. J2 B4 K. C
5 c% O/ Q4 o; v3 \) M9 L- /*设备驱动模块卸载函数*/4 `( V# D7 K/ R. w. P4 n5 l
- void __exit protocol_exit(void)- C" J* A! ^* ]0 [4 ^8 z
- { N$ {, X, x: m! J% O
- /*释放中断*/) x- r" b8 H7 `# N1 I" J/ I% V
- free_irq(IRQ_DA8XX_CHIPINT0, NULL);" F* |1 Y5 L4 j/ c4 {* v
- //释放帧缓冲的内存) g+ J: }& V. A+ E
- k_linkQueue_release(&queue);
7 P; J0 P$ o, n - //释放寄存器映射. @/ E! u. w0 P1 K' U- ]. d- e4 X
- iounmap(R_CHIPSIG);
0 D1 N$ D0 {) h$ i$ W - iounmap(R_CHIPSIG_CLR);: x8 z8 W" g& \
- cdev_del(protocol_cdev); //删除cdev- H/ Q" j; L- d* a
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号
8 |1 `# q" S7 g' p+ f1 x - device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
* z" J: k9 U4 V. v* G7 w+ r4 _ - class_destroy(protocol_class); //销毁设备类
: H; B4 ?8 l P3 A7 p - printk(KERN_ALERT "exit success\n");
9 h+ N+ D5 H7 e - ( O) }& n) `. s7 [5 t& y8 R
- }
. ]: z" Q% I- c! y6 z9 b - //驱动其他部分省略
复制代码
# B2 v9 @) [/ P! @0 L2 g! o
0 R4 S% J j; ^ |