本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑 4 @( ^+ W* E U
. j8 d7 ~+ Q8 [) o( t项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略3 ]* _$ L- f) L0 X- W. A+ A C& y3 ]
- ; v5 U. A% l! k4 I" P
- //引入其他模块函数和变量/ [* h+ a0 W6 H4 t( O: k
- extern Ping_Pong_Buffer res_buff;
/ v5 \! J4 m9 A$ a- L& D4 p6 D
$ M+ y" c9 ] l5 s% k6 R' F- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列
& F1 n6 f9 _ Q, v0 P& ~# \1 m2 T - extern void k_linkQueue_release(linkQueue *queue);//释放链队列
9 c* x7 B/ ?8 k9 q - extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据, r9 j$ k+ [: G0 M7 i" V
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据- S3 g. J( J" Z. f$ B1 Y# h" L
e" I6 ?" M/ J- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化
% @- h! e! j) \ - / L& H2 ^# P$ S! {. ^" y
- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1
+ G* V" \2 C9 y7 U/ X8 E - //设置主从设备号 }+ |* k0 S3 r# K$ I/ B/ L
- #define PROTOCOL_MAJOR 16 N4 |( e. O2 @7 o: A) k
- #define PROTOCOL_MINOR 0+ S( e: h3 i' }
3 K6 l1 D+ w2 N6 b4 y& E( m- * `% [' l; z6 g/ B
* P( {" q; _+ \! X2 }. w' S) n8 {" j- //定义设备驱动的名字或设备节点的名字/ m9 r1 }! [4 K
- #define DEVICE_NAME "protocol_driver"9 m/ K5 n# r9 E1 x* w! ~
: G& g4 m0 |; g- " P6 d! H0 f+ D( W' O$ V
- //定义全局的循环队列作为数据缓冲区
& C5 D& K" O+ B( x; ~6 J8 O - k_linkQueue queue;
) q' T# b4 w" A, v, w - # x8 q) o* ?: [) ~& }
- //寄存器地址映射全局变量
9 ?7 X# l: {! Q; p; ^6 k1 ~ - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器! U+ \) \3 E- Z7 W% c! [( Z1 W3 z5 q
- unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器& w& U. }2 |: N" B! }
! E" s. L% h T1 {! P4 n9 D" `' D- //物理内存映射全局变量- v1 B& h/ T. S2 F7 [
- volatile void *mem_base = NULL;
! n4 r* \- _" K2 G8 N4 J - volatile unsigned char *cur_buf_ptr = NULL;4 c) a! o* p0 i. d7 C1 V6 ^" ?
- volatile unsigned char *data_ready_ptr = NULL;
) H- a0 V( V3 I; C4 k! u
; ]: X8 \' ^& W) y" u( R& X
6 j/ k5 i9 N4 q- 7 |/ ]# F# M3 [
- //定义读数据等待队列头,IO阻塞7 V) r! b/ B3 O$ v8 @# H
- DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);, a$ c$ P* U/ t% B' x7 U
& L$ z+ v: ?) ~; _# w- //定义原子变量# j+ B* G, j8 ^( w& C
- static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备, I. U$ M/ C% C: o$ r; G
, N f; `2 t1 ?8 p$ Y. c- . n' [8 y8 N" r& k/ C( } b4 R9 d# {
- //定义设备类) a1 B) [) q) T7 P7 v; u+ T" J
- static struct class *protocol_class;
: e! h# J: A) {/ V) L, T - struct cdev *protocol_cdev;
/ V, C- S5 l, K% S% Z3 m; f% H - dev_t protocol_dev_no;1 i! h+ s( T- R
$ b! b i% k: |5 S3 J L- /*定义tasklet和声明底半部函数并关联*/
. K' x9 L7 k* w: Z, E - void read_data_tasklet(unsigned long);
3 Y" r7 m* ?* h8 \
) z& \$ m) ]6 C- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);9 G5 h- u) w7 s' l! Y3 l' f V
- //将CHIPINT0_tasklet与read_data绑定,传入参数0
, Z! n; H& [2 ~, y3 r E - % C3 A. _$ ~" v% Y
- /*中断处理底半部, 拷贝内存*/5 h" G( c2 s+ g- Y' [' v. q
- void read_data(unsigned long a)
0 A( _/ j4 U) V0 _6 L - { G" @, O& d9 ^# Y& y1 n' Z& J# {
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1% j+ u9 R. R' Q( G2 t. {- ~! J
- {; C4 p/ @6 L @2 C$ T
- read_quest = 0;! f* ^& l i& c- m
- wake_up_interruptible(&wait_queue_head);//唤醒读等待队列- I* g! L+ n: v1 C: [# J0 l$ k* K
- }1 u$ Y6 P$ U: {5 s; [+ ~! X
) V H! U w5 r" y- }
; i7 x- z4 J' a - ; ]* y- w$ _/ |4 }8 U: S
- /*中断处理顶半部*/& b* D; D- S: m
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)9 A2 S3 v3 ]7 M0 n2 t. U3 p) m
- {
. K: i r- L& i2 X - //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样# O" F/ E: J/ Z7 J( l
- volatile Buffer_Type *next_read;6 u, u1 E- f1 f% t& U. u; |
- //如果DSP数据已经ready
7 l2 S' s+ A! G6 s - if(*(res_buff.cur_buffer->data_ready) == 1)
( X& q- a& [3 n$ J- O - {
+ c5 \! L* T5 L! e! W& ^ - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer
$ ^, ?3 d) `$ e1 }9 Z" t - {- x9 R9 @; K7 ?$ t9 ?' Z) Y; y
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer: c) s, Y) _% i+ W$ s( U, G( W1 Y
- //printk(KERN_ALERT"read ping\n");/ w, F$ F4 i! s1 ]$ k; @1 B
- }
# \ C4 p4 `/ p/ o - else
5 U# o, w7 e+ K# {& z* Z0 W" a - {
; h; l# | r, T' r; P+ e2 ]# c) y( a - next_read = &res_buff.ping_buffer;//下一次中断读ping buffer4 ?. _; o* H* |5 N' P( a+ P9 Y
- //printk(KERN_ALERT"read pong\n");
0 D/ v" a: Y1 V# }0 y4 b$ H - }( e( m0 O+ P. o- k% o* {
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer
7 ~+ F& A( l0 i, ~ - //将数据插入链队列
2 g/ P% @. W/ ~ - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);# ^5 h( Q% Y/ j
- //标识位都重置
: t6 t# {) c0 M2 c q0 F - *(res_buff.cur_buffer->data_ready) = 0;
& h6 j$ n0 a9 N! ~' [+ h - *(res_buff.cur_buffer->data_size) = 0;
$ G8 }7 j) w; `1 S - res_buff.cur_buffer = next_read;
. P$ a6 ~6 e m% Y - }& d3 b* U& a5 b. [5 a/ z+ }
- //清楚中断标识
6 ~$ [1 X# s9 n - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status
3 F5 V* X9 ]/ g, R5 k - tasklet_schedule(&CHIPINT0_tasklet);//调度底半部
" S+ E" P- w' v8 r1 n8 \
1 X' ]& V+ `* J: m& c
0 A* ^, ] G" F- s6 e- return IRQ_HANDLED;
3 }- { N& P( ?% N R - 7 [$ u N0 J; _( e6 |
- }
3 u4 k, |; H: P6 t
' A' k j% g' @; s- //文件打开函数8 C) s8 O. }3 P
- static int protocol_open(struct inode *inode, struct file *file)
6 y0 N9 ], J4 `1 X4 P& f - {
7 ^! I8 D1 q0 N4 d, R% @ - int result = 0;
& b0 \& {* Y( E8 { - if(!atomic_dec_and_test(&dev_available)); |0 d1 l" x0 g+ X
- {
) b5 [% m( h* x7 D$ k+ S - atomic_inc(&dev_available);& `, H F9 c( ]* E. F5 R" P
- return -EBUSY;//设备已经被打开
* ` y# Q: f' j; i$ h- ] - }( T T6 j. a% a
- printk (KERN_ALERT "\nprotrol driver open\n");- [7 M" R$ h2 ~1 d' `9 h
- return 0;4 e; b4 `5 t" w4 N! K" Q! B4 ]
- }
4 C% h9 n$ A9 z! |5 `. ^0 x) x
+ U: J9 \$ c( A# {- //文件释放函数
9 E, \+ p2 p, Q J. ^ - static int protocol_release(struct inode *inode, struct file *filp); J6 I0 Y8 D, Y* y% J9 N- ?$ W
- {' F' v% N& I) q% ?: h0 f6 w( h
- atomic_inc(&dev_available);//释放设备,原子变量加1
$ P: Y4 i- Y/ j6 S0 ]2 O - printk (KERN_ALERT "device released\n");
6 W4 N' a! S; Q- \% y | - return 0;) v5 `: A# D, d u4 g: |8 r3 V( Y
- }2 ~& C5 A0 T+ d G$ F6 I
- 3 a) l5 q8 A/ u5 q! D. y
- //文件读函数
( \; m/ b) ~8 D! H- r3 Y* P+ H - static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)
# g* B. U4 g& m" f6 _4 y - {
# M; _( g- e5 o7 E' L" A% a - int ret = 0;
2 ]# s( f. U, a3 y4 n, y! S/ n5 R1 F$ y - //定义等待队列
. G; Z. ]: w- q7 s) P( d - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列9 R) w9 G. H# n! E" {) x9 B
- add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
! u" A' r( C$ U2 Z, _7 N# c' n! } - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据" _# S4 j. O& G$ f5 S+ M, F( Y
- {
( x" o- ^5 R: t+ `/ R - //printk(KERN_ALERT"\nbuffer no data\n");) f3 }1 N6 M* h! a
- //如果是非阻塞方式读取,则直接跳出 s' Z$ F8 V$ M+ e/ X* v
- if(filp->f_flags & O_NONBLOCK)
5 x1 @4 W! [8 X1 |1 S; }7 D - {0 g( f! l- a% d7 c) J* w5 h
- ret = -EAGAIN;6 L3 }# g4 Q5 h0 P6 _
- goto out;
, l4 @2 r, {1 \9 U/ ~: z - }
: r! Y4 b7 b; P - //阻塞当前进程,放弃cpu资源4 [7 |/ v8 g8 A# G/ N5 G. o2 x! c- O
- read_quest = 1;: P3 {$ y* \% T5 p
- __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠
) P' p5 J. U& \ - schedule();//调度其他进程运行5 ]7 y9 P- \5 }5 h# ~3 H
- if(signal_pending(current))
7 r1 r; P! n5 Y; t - {1 N9 w; ~! f# l
- //如果是因为信号被唤醒,则返回到系统调用之前的地方: x7 n; _# E2 q/ p4 p* [8 U) V
- ret = -ERESTARTSYS;# p/ `' P7 v1 ?: I
- goto out;
+ t+ e8 N# E0 W - }; Z- i: E; }$ u* ?" z0 M' g- w
- }
' y p. n( T1 q - //将数据拷贝到用户空间
7 A9 ~) o( g' h. |+ s, U - ret = k_linkQueue_getData(&queue, dst);
; f7 a2 T t% _1 S/ p1 O - if(ret == 0)- k; |) L& t. Y5 g
- {' ~' m0 f0 ^. C) X
- //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
4 `$ o+ K' L0 N# i& W" \" j8 } - }
+ p5 ]* }/ s: j. J2 Y( V. t - out:4 n/ [. @# B! c2 T, |2 e( Z
- remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列6 O5 H+ n, G L. Z, w
- set_current_state(TASK_RUNNING);//设置当前进程为运行状态
7 a1 v1 D3 m2 X2 t - return ret;
3 ]3 i: g( W# \" q1 r2 @0 a - }
" o+ c; T3 e1 `. H" m5 T
* a# P. L* v8 k
Z- U0 a; p* Y; v G( k- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)$ p4 i3 h* N1 X, s
- {
" b6 [/ k% M5 n- P7 G( Y" |) }' F; J - return 0;
9 P4 C/ U$ _7 T0 P - }
" w% |! h+ N9 S/ | - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行
4 d- k, h8 a7 h1 d, c; }8 O7 ]) z - open()、release()、ioctl()协同调用时被调用*/
+ L5 z! q5 B* ^2 ^* F# G" f) r+ R - static const struct file_operations protocol_fops =! t, g6 C( c6 [
- {
# b5 x2 o9 y" k( `$ o$ u6 m - .owner = THIS_MODULE,5 w: ~. e0 B! `, ^
- .open = protocol_open,
5 l' G5 o+ {. q$ [( x6 _5 o& `" c6 J1 i - .release = protocol_release,
" w+ B5 y' e5 }2 n+ S - .read = protocol_read,
+ a8 H3 F% G6 p* t$ G - // .write = protocol_write,
& e4 |; U1 J3 P) Q$ a- E& v - .unlocked_ioctl=protocol_ioctl,
% o' E! C; w* W/ W& d - };& Q# `9 h8 D1 o4 g1 {3 M
- 5 g5 p% R& y- J* ]
- /*设备驱动模块加载函数*/
; u9 T; h0 U5 e6 W8 B8 l - int __init protocol_init(void)
& K, s" X5 W% ^. {1 X% v - {! R; {" K: \ G
- int ret = 0;) K- ?6 G9 ]# O# h! a! ]1 v1 D- _
- int result = 0;
$ X9 _8 Z9 V7 k2 f% e7 j+ q6 y - //申请注册设备号(动态)
~* _! v0 O+ N, M; m: Z - ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); $ x" s5 V8 @1 j8 S: E. j4 ~4 P
- if(ret < 0)
! Q$ U( V* v: C! R - {+ e6 r+ P9 M" Y7 j- x7 w9 X; }6 h
- printk(KERN_EMERG "alloc_chrdev_region failed\n");- ]" N% N' L2 u# I$ b
- return 0;
9 h; m4 r4 y3 l. o, K - }. M! T; D4 }& O- b8 Z, w
- //分配cdev) V' i! B1 j o: z5 L8 N$ A$ j
- protocol_cdev = cdev_alloc();* i6 O) I9 ^+ V4 \% b1 t
- if(protocol_cdev == NULL); `3 Q1 z' p5 ?) N; M
- {
" b5 G- [1 M4 E0 P; j% z; X - printk(KERN_EMERG "Cannot alloc cdev\n");
5 f1 h. h. t( @5 u7 b- c3 V8 G+ G4 T6 r - return 0;" l9 B; U' V/ o0 m9 z
- }
: {6 g# i# _3 S% \$ U- o# h- [ - //初始化cdev
7 K7 R9 _' P7 S/ X" y" r1 g1 }9 N M - cdev_init(protocol_cdev,&protocol_fops);4 G1 v x) ]. X# x
- protocol_cdev->owner=THIS_MODULE;
- F, n2 H! G6 V v$ D, i - //注册cdev
1 b( m% o) h5 m R) p# s: g0 N - cdev_add(protocol_cdev, protocol_dev_no, 1);
4 S9 E1 X9 k8 c [: s - //创建一个类. z8 Y- R# I; p f. L2 l. B: k
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);* L9 ~& `$ S- ]$ t4 `( ]
- //创建设备节点" P) ~" _; @# T$ f; v
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);0 r! ]( r7 B8 E7 I
- 8 Y0 J% l' {# L: M
- 3 k1 ^2 Y( Z6 E5 s: D! V
- //申请链式循环队列作为缓冲区DSP数据帧的缓冲区; d& {2 ~1 p: D6 ^, \: e! x
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区
2 z: ^0 ?! u# l; \7 ?. ^) f# W% e! y2 z - - L- v9 w6 f) M7 k' y- [4 M, h: w2 a+ ?# U
- //映射ARM的核间通讯寄存器; b# ?1 x" E3 F0 v3 @5 ?: R9 X; K
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
, ^" a0 y* @9 ?( ~0 B- U( d - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);
0 {6 J+ G3 v) C G4 H" k" k* O - //将物理地址映射到内核空间
, s( Y! o" a( W& V - mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);
" n0 r. F3 h. N8 i- N - //共享内存初始化" ?. |# [" F' B' N
- SHM_ARM_Init((unsigned char *)mem_base);
% R( g: v/ O' \8 D# e+ ~* ` - /*申请中断*/
2 g% e8 ~& C( F1 t
6 }- F0 o6 \- P. ]! Q6 W- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);
6 t2 }8 o& T+ R) M - if(result != 0)
8 Q/ U7 Y; t# T2 I - {5 R; q3 O- k& x9 r" {5 i' O
- if(result == -EINVAL)- u# N) w/ N; C" r7 m1 c7 Y, ^
- {3 y, g! y" w2 |- n
- printk(KERN_ALERT "irq request err:-EINVAL\n");
# A' F& n& }& j5 L - }, C" S. A" o4 o) R
- else if(result == -EBUSY)6 E" j7 K2 b5 A
- {
+ s0 m4 U6 v6 g% B/ f5 O - printk(KERN_ALERT "irq request err:--EBUSY\n");
" v' ]: G8 k& }" g- }* F9 z - }
1 W. t! }& E: @5 w - else
8 I j. t$ l5 v3 k$ i7 ] - {& y$ R# {( O2 P# ~3 N
- printk(KERN_ALERT "irq request err: unknown\n");3 }6 A# O7 z" A
- }
3 a. s% B, }& h9 q. N( _6 F - return result;
& y, a- T" ]" g) j. @ - }) d. E) [- O6 H( E: O
- return 0;
( C+ I' Z5 Q, n. M - }2 O5 O/ T5 J% F& G7 z6 l) U
- 5 B( v& K4 ~4 O. ~# l( m
- /*设备驱动模块卸载函数*/
; c# G6 s; x7 m7 p7 r% R - void __exit protocol_exit(void); P( N. U* v% P" e( u1 Z# ^
- {9 B) r& B' O1 ~3 ]' t7 y0 Y2 T+ R
- /*释放中断*/
3 v" k2 g% F5 f% v9 b - free_irq(IRQ_DA8XX_CHIPINT0, NULL);, O$ Q+ f2 x& R
- //释放帧缓冲的内存
8 w. q/ z9 {+ o5 W7 I8 C - k_linkQueue_release(&queue);
% i* q$ j8 n- p7 ]4 v' R - //释放寄存器映射- |: P, ^7 q9 u! n6 V
- iounmap(R_CHIPSIG);3 T6 x0 B S- N @1 a `! Z
- iounmap(R_CHIPSIG_CLR);
3 ^* L8 a M9 K7 ^4 h5 g - cdev_del(protocol_cdev); //删除cdev8 o1 F+ d- ?9 F! C, S: z* P) V; `
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号
D6 M# q# v8 W: [' P. t - device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
- s! J& J& q# P" N - class_destroy(protocol_class); //销毁设备类' _) }, Z( R0 l5 ?
- printk(KERN_ALERT "exit success\n");. H7 Q, [$ Y( l6 Q8 \- g9 m
- ! ]- E Y; v! z" r% o
- }
. _& E. w5 {+ N% p( L - //驱动其他部分省略
复制代码
; b* N3 m7 p' Z7 u3 t) S1 Y0 z+ O6 t
s0 e1 Y- \0 b6 ~% U- v2 ^9 d |