本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑
0 J+ ~* w% M' v/ ~' N {& B, 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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略
, }3 ^4 n" V4 l1 j - & [! l+ K) y, m+ K9 @9 w
- //引入其他模块函数和变量+ P- [* c" X& ?# O
- extern Ping_Pong_Buffer res_buff;" c1 c7 B, f0 ]0 i7 C3 i! V# M; P" E6 e
- 9 W3 i7 I2 b E4 V# `
- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列
: e# h; u- N1 c; Y6 I ^; G - extern void k_linkQueue_release(linkQueue *queue);//释放链队列* S, Z% a2 O2 i
- extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据
3 N+ ]& s9 S2 R% A - extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据) A. X! X4 G1 K, }. s7 V
- ! ]: z1 h3 T5 ?2 E1 j4 F; L$ d
- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化" P% T8 E$ K8 Q% [/ Q
- $ r% K7 _8 j# r/ q$ s
- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1
: [2 ]2 }3 B4 r# h# P8 V - //设置主从设备号, i1 Z9 {6 A" B7 s
- #define PROTOCOL_MAJOR 1
& @! X3 S) G' x0 d - #define PROTOCOL_MINOR 02 ^+ w# Q# {1 b; k: h5 Y: c8 B) p6 x
/ U' [' \' {$ A; J9 w- & t) w! s& m: i- L$ C6 e
- 0 Z4 v/ e8 C' p# O2 x
- //定义设备驱动的名字或设备节点的名字: X' t. v. }. b
- #define DEVICE_NAME "protocol_driver". H# o+ R! \2 M
- * A( Z5 C& e2 o/ i6 J- e
7 ]1 a: e- f6 e2 i- //定义全局的循环队列作为数据缓冲区) \6 U# { L7 D
- k_linkQueue queue;
9 J% {; s2 C1 t7 R# D" Y; l1 ?3 M - 0 f" L6 @7 D, H7 @
- //寄存器地址映射全局变量: @" d9 l, X0 m! y, N6 j
- unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器( i. R7 H0 I1 W, B) f7 x
- unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器
; F8 o( o7 p( j. b+ Z
- r( f, o3 v0 [# m' o# R: V- //物理内存映射全局变量! K/ ]" C( M" G O
- volatile void *mem_base = NULL;
3 w& Y6 B" n# g8 ~/ p& W - volatile unsigned char *cur_buf_ptr = NULL;" u% x! B( F8 q# ]2 f- f
- volatile unsigned char *data_ready_ptr = NULL;
( `( ^3 ?& H) X: d, M6 J - : G A j# f- F6 A- d# l' |
- 6 P" ]& Z2 k! |1 z
% E( W3 G& Z4 J0 k- //定义读数据等待队列头,IO阻塞5 S0 m! {& Q$ y; x- D
- DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);4 w; M" l {5 ?% p% W# [
8 g1 E1 G; V, s- //定义原子变量
& P2 r( m& M3 F: K" |* i - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备
- f8 a1 x& H+ E3 s$ `2 u
4 X m6 `8 E# _( r4 b
* G& W: Y5 W: y0 w3 d- //定义设备类1 q/ z: l( Y8 k8 o) x
- static struct class *protocol_class;
2 o& v+ ?" H, {+ H* |) i - struct cdev *protocol_cdev;& c3 v' d; j _- Q, W; T+ l
- dev_t protocol_dev_no;
# V; `$ B# v% V - . C/ q! C% ^" Z( M5 i% H
- /*定义tasklet和声明底半部函数并关联*/4 ]' K0 l1 S; ]# [. t, V; i
- void read_data_tasklet(unsigned long);
, W6 b* U" _( p, o. y: J - , I- x6 ]; c! ?0 j( s
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);0 g( I2 M8 e, D; d) h$ l
- //将CHIPINT0_tasklet与read_data绑定,传入参数0
: ^: \- N1 f5 ^, j( s" L
3 ~$ A: }. ^( {* h8 q( ?5 H7 i- /*中断处理底半部, 拷贝内存*/6 Q7 }& u0 c% l/ Q
- void read_data(unsigned long a)" I( M. I- u% O2 p; E( |' @2 t- `$ R
- {
! R9 X: r) ^; Q; s' J" T - if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1/ R! T7 ?8 L( T+ _6 ~
- {
# O; r/ \/ ?7 I, m$ F - read_quest = 0;
* P0 \" I0 r+ F& f - wake_up_interruptible(&wait_queue_head);//唤醒读等待队列8 f! S: Q- M" c1 q9 w6 x8 q& P: B
- }
) H7 Z( A7 X2 `* Z
7 I* h7 P, o. c2 W2 [- }
+ z/ y* h: c6 N: f+ k$ r" q
' |, t- y3 H7 @# i( [- /*中断处理顶半部*/, Y: J5 \3 f. _: X8 j; W
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)( e$ L4 g, l9 A0 p
- {
! D9 T5 s+ a' u+ w/ @( ~ - //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
0 ~% Y+ c. ?1 @6 Z5 I. J# Z- T' Q - volatile Buffer_Type *next_read;
- c! J% V7 ^/ E" E - //如果DSP数据已经ready' C& l# R1 f& i7 N. t7 w+ Q7 V
- if(*(res_buff.cur_buffer->data_ready) == 1)
, \) B" P# d7 R8 f! `/ `( n% ] - {4 u5 c/ Y4 F" g) ]( Q- x
- if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer) Y! b6 z' y* `
- {
/ c/ u2 h% V0 A3 c; ~3 g - next_read = &res_buff.pong_buffer;//下一次中断读pong buffer# ^9 I9 k" Q; ]7 [" ^- c1 Z
- //printk(KERN_ALERT"read ping\n");
5 {0 r# {0 @. d l9 T - }
; v' D& H/ [5 N/ k, U' L - else
0 {5 }& R. r# D - {
- C+ S- M6 ]. H* ~' M2 U. H - next_read = &res_buff.ping_buffer;//下一次中断读ping buffer3 Y( c. \+ g. l# V
- //printk(KERN_ALERT"read pong\n");. L0 ]9 h7 R# c+ w2 s
- }
3 y/ Y' K4 _( ?' @ - *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer
& A: L7 ]2 L/ H; N5 U* G5 P - //将数据插入链队列, ^7 Q7 g2 l" q8 _ ~) ]
- k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);
) H" M; |& m. K% A9 P - //标识位都重置: m4 q1 u# c6 V. @
- *(res_buff.cur_buffer->data_ready) = 0;
, }! Y$ _7 O) Y* Y# ~ - *(res_buff.cur_buffer->data_size) = 0;) ~, h' v' _8 y& k, B
- res_buff.cur_buffer = next_read;
& x$ h2 ?( j4 R4 G - }; ~+ a5 q Q a! ?7 I. U
- //清楚中断标识
- }2 [ O+ G: C4 l - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status
% v3 Y; L' d) ]2 a. x' l8 q - tasklet_schedule(&CHIPINT0_tasklet);//调度底半部 ; X) M' R7 e8 c# |: i$ U s
- 6 p! m1 p6 w5 e
- ! ]- b1 V/ C! r5 [
- return IRQ_HANDLED;% X$ \! I) C. o1 e' w$ M/ E$ W
) I% \. U) `% O! [- }
C) y6 O$ M* z5 n. Z# H
$ p6 J0 `" u" {- //文件打开函数- e& r" S( _, K% |
- static int protocol_open(struct inode *inode, struct file *file)7 `1 b# a$ K8 d I. J
- {, l* x$ v& T8 h
- int result = 0;6 g* @% V- j+ O* |, x
- if(!atomic_dec_and_test(&dev_available))# Q; {% C, O( o4 H5 h9 T' m
- {" r# d& c5 @9 I+ A) Q+ ^9 @
- atomic_inc(&dev_available);
4 A; O- R) K' L- c - return -EBUSY;//设备已经被打开
( Y/ b- g5 Y- {, F: a7 ?) l - }
1 Q1 Z0 l# e, D5 ~" v3 @ ?4 e4 d - printk (KERN_ALERT "\nprotrol driver open\n");' L$ {. @$ ?; Q3 @
- return 0;
" r1 @3 b/ x: ]- G0 A7 H - }
% l- ^8 p6 s' U" |' Q w9 }6 X
* i! p' Q9 Z) M. H, ^8 M! ^- //文件释放函数
" _. P" \' B8 a, p* v8 ?, M - static int protocol_release(struct inode *inode, struct file *filp); l6 W+ O. p; M, g
- {
& S5 v) e2 ^' l, G - atomic_inc(&dev_available);//释放设备,原子变量加1
3 i- p- v8 K; G& ? - printk (KERN_ALERT "device released\n");5 ~0 L; b: o+ V
- return 0;
* c: D0 t: a4 n$ z$ i% d# _ - }
, c0 c9 v3 Y; G6 N7 f# b# P- c" H8 f - 5 c9 ]( F. J) n! O
- //文件读函数3 d- C/ _3 R. [0 M$ n1 n& v% Z
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)
6 a/ }+ s! O8 L* p+ y O5 _ - {8 { S6 u. ]! j, t
- int ret = 0;2 Z9 |+ ?5 g0 F$ Z' T
- //定义等待队列
# H7 u! ^1 D, F) G2 M; N( L9 v - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列
2 o( h$ B& {5 q/ N7 O, W - add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
1 T% Q0 m; o7 e3 D - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据, `4 i+ X3 p! s. ^" }
- {
8 {) h8 l9 l* s) g2 d; q8 V - //printk(KERN_ALERT"\nbuffer no data\n"); q# o2 x2 h- U2 z
- //如果是非阻塞方式读取,则直接跳出) o( d6 w0 M( c6 x( V1 h
- if(filp->f_flags & O_NONBLOCK)/ b, {8 J8 [. ~7 v; b" G
- { {$ A7 A9 r& H- e) ?5 }2 G. T
- ret = -EAGAIN;
) Y9 ]! |( r6 {$ t z6 h - goto out;
; N+ A. F. U' x r; c/ U - }
) o1 ?5 J! X5 k6 c, { - //阻塞当前进程,放弃cpu资源* W; l& r: M' y5 P5 _( l
- read_quest = 1;
+ X) s2 W+ c& q, m; j- P! m - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠
* b$ ^! U" h. W8 S g/ X - schedule();//调度其他进程运行5 ]7 I: v3 o2 H/ B$ h
- if(signal_pending(current))
" |+ X. @" G) u8 E - { x/ x5 n! b2 L: ~
- //如果是因为信号被唤醒,则返回到系统调用之前的地方
1 Z0 s0 f: d, \! R - ret = -ERESTARTSYS;
, V: F/ a4 A" v% g3 \) I7 G - goto out;
7 ?6 J+ \, ]2 f' P - }
9 c' D) o& t9 ]; v- y - }
( k; P* X& Q' z1 S7 H! k/ Z1 ?' \ - //将数据拷贝到用户空间8 U9 v+ g( |9 n2 t
- ret = k_linkQueue_getData(&queue, dst);
$ D% p! B8 W, f5 F - if(ret == 0)7 t, ~8 D: v8 A2 t6 I, y; F
- {/ e+ u# E+ b) a8 U: H4 ?
- //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
- E% P% \. I9 g7 c& j - } D% q1 D O! J9 n( [0 P! z8 I
- out:
) k( w+ O: L& M - remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列% @* X* v- ]2 Y" R* `) s
- set_current_state(TASK_RUNNING);//设置当前进程为运行状态0 i( t# g$ L6 p- ]1 _, o
- return ret;
- M& y3 e( S' R7 O4 `, G - }7 ^0 b2 r( q/ r7 y1 c: W# v9 a
- : o' S/ C% ^9 f& h7 H5 M
% v& a: Z% _& r: I- n: S" _- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)
. q6 `9 X; } _! |1 N" n# j" g3 z - { q( F# C- a; m5 h0 b X# x5 b
- return 0;
2 O; V* |/ f6 b- E1 H# W: J - }& R. y0 ]4 I1 _" L
- /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行' H. A! Q# _0 x1 m! r) t. r
- open()、release()、ioctl()协同调用时被调用*/
' M" U7 J6 H1 ^8 W- x - static const struct file_operations protocol_fops =% W+ [% s$ B5 }
- {
7 X- B$ u' Z$ P9 Y9 \ - .owner = THIS_MODULE,( R) S& n& D$ e
- .open = protocol_open,( m, G* ?% X9 n( [" h
- .release = protocol_release,
D- p5 L2 v# h! N o - .read = protocol_read,
( Z- W. ~4 D0 [ - // .write = protocol_write, T8 K9 n( T$ f' L& ~+ h/ X
- .unlocked_ioctl=protocol_ioctl,
/ V3 D5 Q/ ^! {1 B" H+ Y - };9 `: h& ^+ o/ E3 _/ c1 C* `. R* X7 ~
- / V% K& U# K0 b3 x- m% g' G7 O
- /*设备驱动模块加载函数*/* N5 Y: t7 y4 U
- int __init protocol_init(void)& Z( n8 `; S2 b" ?% ]; i8 A
- {8 G% }. t( @% V( h
- int ret = 0;
8 G' m, d4 J2 I: C \0 x8 d5 ?3 @ - int result = 0;! Q9 _) r. j; _- ?$ q6 @
- //申请注册设备号(动态)
! ]2 I* ?7 u8 @) r/ G - ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); 3 p8 A& {7 x1 r B. @
- if(ret < 0)
" e$ J" {; f/ V& ^ - {1 Z l/ Z7 K2 k/ _: n+ D
- printk(KERN_EMERG "alloc_chrdev_region failed\n");
2 L4 B! c0 I) X% B - return 0;* I# h4 ^6 u) U" k y
- }% X0 }4 e* r, M& z
- //分配cdev
3 i3 N r2 ]$ n$ z+ L( d" V! Q - protocol_cdev = cdev_alloc();
: v3 `! J* M/ F$ N! j5 Z# B. s - if(protocol_cdev == NULL)$ f3 D/ ^9 o9 s+ v3 l
- {
9 Z9 `; ^ y4 M' T) ]3 G' ` - printk(KERN_EMERG "Cannot alloc cdev\n");/ B& P, R) ]% }$ [
- return 0;4 A2 ?# \' e( o1 h
- }
' t' L4 ]$ G! Q - //初始化cdev" f: J4 d; E/ s/ R2 G6 L1 B K: c& i
- cdev_init(protocol_cdev,&protocol_fops);' Q$ X- r" |& m$ p" z6 P/ Q3 R
- protocol_cdev->owner=THIS_MODULE;
6 S" `; E" F, I0 p: \ - //注册cdev
" O3 A1 k. H) ^, C% ]- z - cdev_add(protocol_cdev, protocol_dev_no, 1);
( z( z. H) E, E" [' g( F+ W, f - //创建一个类8 ? j/ V# @& A$ ? z
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);
7 }) s( w: Q& z. K0 h - //创建设备节点& g8 S0 `4 Y# x8 `+ \" r& K& {9 v
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);
. S. {* k0 }; ]/ L$ B1 i - , B) \/ U' f# G: T: V- S
- : O. Z0 [# @' K1 Z& M5 }: O: C
- //申请链式循环队列作为缓冲区DSP数据帧的缓冲区
) G; G) V* `4 q. D0 {4 F& l - k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区
% h* `* `! H$ N/ ?, I' v
; |7 m: e8 F) i) ~, P- //映射ARM的核间通讯寄存器6 Q3 h1 ~1 n3 V* K
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);: {6 d2 `( k2 m
- R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);1 O4 \: \' @) U4 e& l. B, h% G
- //将物理地址映射到内核空间* u. v7 c" N7 U- _' J& ^
- mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);) @: u# T9 d" w+ J9 b
- //共享内存初始化
5 n. e1 E! f% [# ]* W - SHM_ARM_Init((unsigned char *)mem_base);& m* \* A: R: i1 }& J
- /*申请中断*/
; ]7 ], v6 p" ?( M9 h+ j. K - ( Q* d. m- q; x8 O. t
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);$ ?+ t5 d- F4 c* S l$ [* r) z$ `9 O3 z
- if(result != 0)
3 q$ A3 A9 |+ ? - {3 p6 Z5 y/ G$ g
- if(result == -EINVAL)
( m# t) U7 ?$ S" A) V& S, { - {! `( S$ L( p" Z- P$ C' T# G) c
- printk(KERN_ALERT "irq request err:-EINVAL\n");2 S7 p. @% U' j* @# T6 @
- }- a1 W' X0 C/ R. Q ]3 j
- else if(result == -EBUSY)
" V$ v" t0 c$ c6 U( r) e6 { - {# r" \% L% x7 c+ v0 b- V3 `
- printk(KERN_ALERT "irq request err:--EBUSY\n");; B) P, b) G! _/ ?1 ?2 n( @
- }# l; F- E3 d& ^! k
- else
6 a: v# `2 a. b/ C! n - {, r9 `5 H9 U: G, u8 P4 U. ~
- printk(KERN_ALERT "irq request err: unknown\n");
0 A( n4 k$ ?- @4 |9 V6 R O - }1 H ]5 T: Z4 x0 i
- return result;2 [4 X% x9 R8 `6 I5 P8 n
- }. H1 r8 a2 m6 o2 P5 y
- return 0;, H; d# R, ~$ d+ Q' h- W
- }
. S7 b9 H7 X- b4 v/ I% v; R - & D4 |- S# J" [# W# w) J& _& _
- /*设备驱动模块卸载函数*/
4 f0 H- r; A- z - void __exit protocol_exit(void)
" I2 r9 Y2 \! q. u& j: e3 i- Q - {
n0 q2 m0 e2 {5 v% `5 I - /*释放中断*/2 t/ Y8 N( e. c0 D% {/ T. j% f
- free_irq(IRQ_DA8XX_CHIPINT0, NULL);
- t# V7 Z, S. q% e - //释放帧缓冲的内存7 ?4 \# ?: [# P- R* L. P
- k_linkQueue_release(&queue);, \ ?8 i* K0 q W: q- G
- //释放寄存器映射
. j6 R4 o& g6 H; \& B - iounmap(R_CHIPSIG);; X: b5 o8 L8 i3 V& k
- iounmap(R_CHIPSIG_CLR);) L' x# ]$ q2 a: r
- cdev_del(protocol_cdev); //删除cdev; ^* C) t* t1 \, m8 _
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号 D4 G' [9 |; E" N+ d5 h$ u. G2 A
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
1 N. h+ a7 A: |& ]8 K9 U) l& q - class_destroy(protocol_class); //销毁设备类! K' t7 q, \- S
- printk(KERN_ALERT "exit success\n");+ x# e' h( W3 h7 F! H. K* Q, g0 T
- ; Y( N: A$ d( Q I# b/ E/ Y3 ?5 A4 \
- }
( H$ O" j8 b8 u4 `& P - //驱动其他部分省略
复制代码
- q8 n+ F# h) V% |' E4 |7 }4 h( D
|