本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑 ' }0 Y4 S6 Z/ B
5 _# J4 G5 Y9 N# B! `/ j) ^
项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略; R3 i- C/ @ M- E
- / x9 T0 n; f. F) j4 q
- //引入其他模块函数和变量
! k0 G6 V. t) T$ l& { - extern Ping_Pong_Buffer res_buff;
q: k7 w: }. D: \/ B
3 q, b) O$ ^6 z3 _+ P3 D" L( C- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列$ t4 a/ ^8 s- Q T" V/ F
- extern void k_linkQueue_release(linkQueue *queue);//释放链队列
# D/ K( y- n5 \- Z4 Q& r' Q - extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据
1 {# {2 L3 i" s; o7 o& |; `9 G - extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据
7 H, S; e: i; A+ O5 U) x
' {% ?. \# k! G- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化
( J2 j3 p& h( j) }& A S$ }
; b7 c) s2 p' k! q; S- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1+ T: f8 X, X. U8 t& p2 \: f. |/ Q6 p
- //设置主从设备号8 t1 Z) V6 P2 z/ p: e( Q3 d
- #define PROTOCOL_MAJOR 11 Z, V! \* |2 v( Z$ w2 e
- #define PROTOCOL_MINOR 0
8 E# P. }3 `' T0 N7 }3 t& N
2 k) `- ^: ?9 Y& d1 r- 0 A2 m' W& I1 t+ s. ?
- 6 M) e+ D# G* R8 ]
- //定义设备驱动的名字或设备节点的名字
6 X L+ F' z3 W, `, o8 N - #define DEVICE_NAME "protocol_driver"
+ A9 [5 f% u9 d4 Y2 W" P6 f/ ]
8 }* A# s, _% L( W* c
+ M& T3 Z6 X( A* a- //定义全局的循环队列作为数据缓冲区
0 X7 h; \6 d- I2 Z2 | - k_linkQueue queue;4 @! Q; p/ n7 K' ~6 c6 i
- * Q# X6 F. e& T) D: }3 X. W
- //寄存器地址映射全局变量. k- j' I# N9 C A% L: v( Y) ?5 A7 E
- unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器
" E9 k: H3 y3 P7 | - unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器
7 F4 v% P$ ?" g- R+ ^
+ {$ R" @7 }1 ?! g( o1 [- //物理内存映射全局变量
1 l6 R8 \5 E& ?3 V% x( l+ y - volatile void *mem_base = NULL;& s! t) z# E) U+ t- ^7 {
- volatile unsigned char *cur_buf_ptr = NULL; J/ Y% x+ |* U7 ?, r3 m+ o; W
- volatile unsigned char *data_ready_ptr = NULL;0 z( J6 \" |) f
- & L/ f& [5 Y8 ^1 p2 b, c* C4 H$ }
- , ]- I6 z# S: d+ Y9 V
- : l/ X4 H# Z, [0 p# h( _
- //定义读数据等待队列头,IO阻塞
$ Y. t6 s5 N$ ?) J- Z - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);/ d6 _- E+ p" N ~! }& i1 ?* h
- 4 A$ u+ q7 X1 E$ c8 j! {9 T
- //定义原子变量* g" H* {2 t6 `% T9 L4 N
- static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备
t! G* \- A( p* F
1 ]; L$ _8 a4 L1 T p0 y* B. C- ( b6 x: r: G7 X5 E
- //定义设备类
0 @ i. O" r# G4 O - static struct class *protocol_class;
; x+ o( L5 o; T8 J" p - struct cdev *protocol_cdev;
+ h# W6 y0 _( p7 u - dev_t protocol_dev_no;9 u: l5 Q- a9 f+ J+ f" w
/ h! j# a4 y# O9 j. F- /*定义tasklet和声明底半部函数并关联*/
( f1 A) a$ m# t+ R - void read_data_tasklet(unsigned long);
/ ^$ [* h& m0 y% {* I- m) a
3 S2 E0 T7 t! T6 J6 S! ~' N. a& D" W- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
1 F9 B& V; [ h, f/ C2 n+ B# r - //将CHIPINT0_tasklet与read_data绑定,传入参数0
! r5 }- Z# m* m4 a( k' M- m- {- N, |! x
# Q) N9 Z h0 w* Q1 V9 u& V5 `- /*中断处理底半部, 拷贝内存*/8 X) H9 {) l! D! v
- void read_data(unsigned long a). t' B: Z* L: n @1 N P9 T! P
- {$ l( L- a! m/ L: [; C' k
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为13 C5 Y7 H4 @% ^- m
- {2 }7 G) U7 j: G; O |0 F" q1 L
- read_quest = 0;: S5 Y J$ d. q& h q
- wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
" I; k, c* L8 B7 a - }
7 j3 A" M; p& ^1 l# O: E
$ h: [/ C! X' H% S/ _% J6 e8 ~# T- }
' m: ^5 H; u8 V- C - 7 H. O8 ^6 Z7 V; M9 I3 d
- /*中断处理顶半部*/+ r" m6 c9 ^1 |% D8 v Z
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)
, p* {# m3 n8 V" g/ B: L$ f/ ^+ d9 V - {
+ [* t+ E1 e6 ~0 L. J' O - //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样' I- G' H* T" e. d' N! c( ~) J j
- volatile Buffer_Type *next_read;
' q! k: M2 g( s. u/ G) j - //如果DSP数据已经ready
9 v+ h9 h; o2 E( N# t' M' k( i - if(*(res_buff.cur_buffer->data_ready) == 1)
2 ~1 E c/ {( Z# { v - {
$ E4 n- l" W$ Q8 _) ~) q - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer: D0 D2 h" I# f* j+ r2 I+ T( K- ~
- {
& U* f/ f6 C3 B0 e: s8 x) ^ - next_read = &res_buff.pong_buffer;//下一次中断读pong buffer% K# \! G" \8 V, x4 k
- //printk(KERN_ALERT"read ping\n");
$ l3 V+ ~. T. Z" ^- q! |) Y3 ^. E - }
* I4 U7 r d7 |/ x2 N - else, b& M9 ~ m' U: R+ }9 N
- {
9 z- l1 _ ^: e2 l8 I - next_read = &res_buff.ping_buffer;//下一次中断读ping buffer
, c+ }3 M/ t( i8 h - //printk(KERN_ALERT"read pong\n");) }: `* [$ E) \4 v* x
- }
. [2 ] G$ g1 k7 m) B, K1 q3 l - *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer: o4 c6 y) L1 d) w
- //将数据插入链队列
* a& f4 m( h1 q. ?3 s - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);
4 u% V4 `# R% x - //标识位都重置7 F5 r* P) J7 `) @
- *(res_buff.cur_buffer->data_ready) = 0;
7 K. g0 S, j) | - *(res_buff.cur_buffer->data_size) = 0;/ g) s% L# M3 x
- res_buff.cur_buffer = next_read;
# A& I0 ~ q6 z e# N: i" c - }
% j" L7 l, n& R- d; O- B7 O - //清楚中断标识
0 I* p$ q+ t8 q; X/ h - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status7 W2 ?8 L# r; V4 j( o' U
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部 q8 G4 ^# s! I s7 |
8 S, b5 t9 P" V7 M1 y- " X2 i& N" V0 l
- return IRQ_HANDLED;
7 s1 n. V1 t* k5 r; S" V0 y - & `& M! @# u# y7 C/ f Z# T) G
- }6 g6 m" [( r3 p' O0 X
( ~$ M/ @% ?* \; ` [$ K- //文件打开函数5 e, J6 r4 [- d6 B
- static int protocol_open(struct inode *inode, struct file *file)
0 Z N, n; G* ^) N* i3 a# L( J - {
9 {4 E& i' @" m! w! Y - int result = 0;
; [ ?4 ?+ J# M! g" V - if(!atomic_dec_and_test(&dev_available))! L! x5 o1 g0 c; y' W+ i( Y
- {
+ K) M" q1 x9 ]5 a+ c/ h' ? - atomic_inc(&dev_available);" P2 P% `$ x# d
- return -EBUSY;//设备已经被打开
8 ?# y/ t+ m. q5 m H( j - }- t G+ v- }/ Y5 H9 \
- printk (KERN_ALERT "\nprotrol driver open\n");
+ r$ }! V4 i7 V: d - return 0;, W( g# A" G8 P9 r! l3 e2 t
- }
0 j9 m8 \/ v5 l, w* Z
& C7 L& Y# c' U/ @7 ?' f- //文件释放函数
. z6 Q4 z+ o2 }- r - static int protocol_release(struct inode *inode, struct file *filp)
* L* [" K0 s5 [+ p2 s) {4 } - {
! N& ?% M: U3 Y3 ?8 E! g8 a& Y - atomic_inc(&dev_available);//释放设备,原子变量加13 t* z. v0 A* \3 ]2 [+ h
- printk (KERN_ALERT "device released\n");
Z3 r9 O- |9 u! ], k5 O - return 0;
$ h# c7 _' a6 f2 L - }, @. S7 ^0 B& z% J
" N0 b! H: ?: J9 I, j, ^. m- //文件读函数
. \ ^# V! l4 U& h - static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset). a/ u+ d/ K' w, r- s, X/ y a
- {1 S4 j) D& o+ k
- int ret = 0;, \6 {1 Q6 q, j* O0 _* G
- //定义等待队列
% @" j4 C: L& Z9 K1 C! X. l - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列
0 t" q$ Q4 n4 }. _. J - add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
# z, Y2 U- p* t( u3 F, R - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
% @' ^- x, o* ~ - {
8 Y0 }* ^3 u$ H; D6 I - //printk(KERN_ALERT"\nbuffer no data\n");
& ^; \( ^! r5 O6 [- a2 D% \. }& d - //如果是非阻塞方式读取,则直接跳出$ ^+ ?2 v" Y8 Q% J
- if(filp->f_flags & O_NONBLOCK)0 ~1 _2 u( C$ H3 c( B
- {; ^0 s( B8 H& ?; ?- x
- ret = -EAGAIN;
, O6 Y% H Y1 Q" f& H/ l( V - goto out;9 Z% I: l2 V, j m
- }
+ E) j+ j) h Z6 C5 c - //阻塞当前进程,放弃cpu资源) n0 s v! u; `5 x
- read_quest = 1;) _( l' g/ Y$ g7 G: }
- __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠
$ S! p7 G7 ^. J# _3 H - schedule();//调度其他进程运行3 |* c- V$ g$ a0 H
- if(signal_pending(current))
& n$ m6 i3 e/ N$ G) k* f - {# \2 A+ T3 s; `
- //如果是因为信号被唤醒,则返回到系统调用之前的地方0 G/ A. }, m: _8 n/ I
- ret = -ERESTARTSYS;( c, |3 H+ c: i
- goto out;/ U% D7 k% z9 u; ]2 N$ I
- }
; F/ W* z l& k# k* H5 y - }6 K/ o2 ?1 ]1 O- h
- //将数据拷贝到用户空间
" R8 u! e4 Z* [4 f+ i- k h& A - ret = k_linkQueue_getData(&queue, dst);
+ [8 ]6 Z% t$ D - if(ret == 0)6 d9 n* @; ]: D" ?2 { Z$ s) y& ^
- {
1 A2 M. c: I. C$ f! o - //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);% K+ A. `* S2 j2 U ^" s
- }& q% B1 m& t* _- B- @$ i5 y
- out:9 h* Q5 ?- Q" d w; i2 H4 ^
- remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列
7 g/ K: U7 Z, |! u$ Z6 P0 w - set_current_state(TASK_RUNNING);//设置当前进程为运行状态
. U b; `9 L5 l6 { - return ret;' A9 N" a3 c1 D, b) O
- }
% D9 D3 G3 ]+ A; [/ h: f! P - 6 v4 T( r+ ^! t9 t! d$ W
- : i8 h5 w. n7 T# n
- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)# a# M E5 ? ?/ G7 a2 W i: `
- {
( h- y9 _& }6 G - return 0;8 {9 v5 p* Y; B5 L+ i
- }8 K6 c; D0 g+ p9 Q7 w
- /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行
# l) e# g; k) Y: W6 i+ u, d - open()、release()、ioctl()协同调用时被调用*/
% S/ d5 ^, \4 }: a) i - static const struct file_operations protocol_fops =
: `8 g3 `* F) j8 e8 \; J* ` - {% ^' N, Q5 Z5 `/ q6 _ a, F
- .owner = THIS_MODULE,$ R; w1 _( S( h. c& Y
- .open = protocol_open,
3 [* X. ~5 { E' @ - .release = protocol_release,
0 M# z) ^! h: k$ o9 p U/ n - .read = protocol_read,
! T, }8 ^( A m - // .write = protocol_write,# X o' R( j; m+ c
- .unlocked_ioctl=protocol_ioctl,( m# o9 [9 F, K; l, G
- };
2 F4 ~* b# V7 o, T
- T3 R# u; k; B- }$ ?. ?- /*设备驱动模块加载函数*/
( W+ X L8 ~2 Z - int __init protocol_init(void)3 s, E8 l1 A! k; ]' G; ~7 z
- {
/ a. F% |, U4 x# \: ^ p/ U - int ret = 0; h; }# f/ q B
- int result = 0;5 w h) Y# n% f
- //申请注册设备号(动态)
+ H2 i1 y/ y# q' P- k4 O* D - ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME);
8 N; a" U& z) p- c5 b* G+ X1 K8 p% I - if(ret < 0)- l* b/ N# u! z9 Q8 F8 c
- {
& _: G9 N; O9 k Z# }$ h - printk(KERN_EMERG "alloc_chrdev_region failed\n");
, [ ~7 X4 M: S - return 0; R6 o4 J) N# i& ~; g
- }
; ?6 D+ k% s- Y - //分配cdev O' z* A5 S7 g3 ~4 m$ V7 c
- protocol_cdev = cdev_alloc();
8 g5 z, Z3 t6 @# v' {9 Z9 D; C - if(protocol_cdev == NULL): L) C8 L, |4 [* s$ o! E
- {
4 ]. p* y) l# {4 R' P3 ~' A( E - printk(KERN_EMERG "Cannot alloc cdev\n");
: v# E2 M, B, i7 ?5 c" H - return 0;
' w5 H2 r7 P E8 H3 B: l - }
( H$ g5 n% f$ T& Q - //初始化cdev
+ e% L8 d- S; \" J- t5 V4 B - cdev_init(protocol_cdev,&protocol_fops);
6 D2 G& t$ `, V9 r& Y - protocol_cdev->owner=THIS_MODULE;
" A3 |4 b! T6 @ - //注册cdev
9 T2 _; x0 B% c1 O - cdev_add(protocol_cdev, protocol_dev_no, 1);
/ Y# Q# f( M, U6 ?! C% S2 z - //创建一个类
- {7 _: b; b8 M+ z; g1 O - protocol_class = class_create(THIS_MODULE, DEVICE_NAME); G1 Q. Y2 x4 u7 D! f
- //创建设备节点
! W9 ]* b# ^& X - device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);# r# U5 h( G! S7 z8 Q; C
-
4 q+ ?% A& L# N8 H - 0 G2 C: y: C. M1 L
- //申请链式循环队列作为缓冲区DSP数据帧的缓冲区
9 w! \8 j; ^0 W& m6 R. d - k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区
9 K4 }9 Y" z8 j9 p4 f$ S9 P0 Q - ( X% [6 j4 k M- i2 d" n5 M+ c' y
- //映射ARM的核间通讯寄存器$ _/ M! J3 u9 j g
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);$ ], Q6 p+ `$ N! G5 ?, l" A
- R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);, w+ y. B2 B& u3 I
- //将物理地址映射到内核空间
# {/ Z3 E/ s' v# L - mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE); N' U- c3 f" C3 x6 z7 x7 K5 |1 A
- //共享内存初始化
- ?! t' @1 f& D - SHM_ARM_Init((unsigned char *)mem_base);
0 {) s, `& X: r - /*申请中断*/! b; D' f9 O' T( b$ q; b5 G9 g
- i7 ~1 l4 K( `$ {
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);& s/ P( M; Z* p$ A+ ]
- if(result != 0)2 W+ j8 t/ G( L# B" y
- {3 w; J6 k" ]( x+ e$ V! L z$ R
- if(result == -EINVAL)6 v: O4 n7 p0 j( `# _ x0 V1 B
- {
3 A) ?4 v9 u% r3 Q; ~ - printk(KERN_ALERT "irq request err:-EINVAL\n");
6 O8 q$ @8 |9 b- g6 [ L/ @ - }/ D- C7 [, U0 B! t1 E& d3 n, Q
- else if(result == -EBUSY), G1 e* w. b) y% |% i- j
- {7 A* X3 I4 }+ A m2 M5 u# V
- printk(KERN_ALERT "irq request err:--EBUSY\n");/ [8 G! I; d" G
- }
- w9 J% K) g) K/ L& i3 u2 `7 z$ z+ I - else
" C2 [# q- z& t/ }: o" U - { |: W$ ] w) g) X! I2 z3 w
- printk(KERN_ALERT "irq request err: unknown\n");
$ g% l" g- \/ _ - }
; k9 G7 Q$ I% ~( a# E* C* R - return result;
- m4 v5 _: T7 i7 ` - }) j1 C7 e& o9 L# v! @. m9 u, _: _' {
- return 0;
6 l1 a' s) M& m& J# {$ h( { - }" O8 Q# v+ V% e3 c
7 x% m; j# e; P2 p- /*设备驱动模块卸载函数*/) F+ I! _4 ~- O. i( ~
- void __exit protocol_exit(void)5 R* N1 R; B, q q5 _
- {) O9 u5 O7 i+ a
- /*释放中断*/$ @ J+ J r _
- free_irq(IRQ_DA8XX_CHIPINT0, NULL);( h. x V7 h; C% e/ H
- //释放帧缓冲的内存& t4 Q" n* T; L
- k_linkQueue_release(&queue);/ e9 X/ E" V% k1 I7 I0 b
- //释放寄存器映射- `. j( C' s5 C; b9 e) K- N0 V) v
- iounmap(R_CHIPSIG);
; v; ?0 n* g3 T0 { - iounmap(R_CHIPSIG_CLR);
! X% d* m2 ~( v( o- r9 o; z9 ~ - cdev_del(protocol_cdev); //删除cdev
3 u9 T2 {& r; F* ~: ] \( Y7 @ - unregister_chrdev_region(protocol_dev_no, 1); //注销设备号
8 e0 `/ W* D0 P$ m* M4 m) Y" S - device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
* s4 e0 J8 f# D9 O - class_destroy(protocol_class); //销毁设备类
I/ `! t6 J/ d6 H1 u4 ]+ N) Z - printk(KERN_ALERT "exit success\n"); Z$ j. G3 M/ G' e: V" k
- 8 g% l; t, J0 A/ u$ q/ _
- }
: F6 \! e" f0 C* B9 G X - //驱动其他部分省略
复制代码
3 c; g! s0 O6 }7 A6 Y q6 n6 k9 P. n* u5 F! S/ C) X
|