本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑
7 t1 d' h9 l( M1 R+ W; v' J3 n" G C: y2 N' R
项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略
8 F; J. E0 E3 R$ b+ i5 i- P
: k% \ J# _/ O- //引入其他模块函数和变量$ L+ d% ^* L7 ^5 \8 \: L, n
- extern Ping_Pong_Buffer res_buff;
* R: u5 m' j' t) V/ n2 h - 7 \+ v: `9 x1 B# I* e
- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列( m2 e3 x9 s3 ~0 d
- extern void k_linkQueue_release(linkQueue *queue);//释放链队列
0 ]' c! v! S6 `8 B6 M/ U9 G - extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据 a+ E4 N1 |! a
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据& E- d5 k4 }$ Z o; ~4 h! B x
; [% H+ _1 d/ _0 @) S9 k9 F% e- G0 Y( T- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化
w% ^! C9 w9 R7 \* A/ ?5 R - 3 D; u& Y# I8 |: S
- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1
. D; s _2 y& s9 k/ [, j; ? - //设置主从设备号+ [2 I5 v; i- o8 h/ ?1 i6 T
- #define PROTOCOL_MAJOR 1
* p% ?4 e7 @2 c% A; }* ~4 J- G/ H, c - #define PROTOCOL_MINOR 0
/ z. l/ T `- T6 R
: Z6 n& B- q- F2 ~
4 i' E8 D& u2 S- E
, J D& X: o& S' N- //定义设备驱动的名字或设备节点的名字
- J0 w5 Q% a/ P5 I' O - #define DEVICE_NAME "protocol_driver"
7 L( S+ h. E7 i! {1 O J: Y. d% _
( p. o# `6 x. Z) c0 w
$ Z( j, G3 P+ n# @4 [7 Y- //定义全局的循环队列作为数据缓冲区
4 _2 Y2 z# [. G6 |( P - k_linkQueue queue;! t2 C' x& e) Q5 w9 ~7 L: A5 W2 l
- ! X6 A% x4 m! f1 L3 m: _
- //寄存器地址映射全局变量% P$ G; k i! ]2 T' i n1 I% `
- unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器
) G% H A+ t; q' O/ Q: a - unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器/ ]% G' ~2 |/ D" Y& K0 O
! [' Y1 D' y: s+ ]! o" u4 f7 l- //物理内存映射全局变量9 e. V# t3 w& Q+ Y( o+ F/ ?& X
- volatile void *mem_base = NULL;
7 z2 J. A. f; V) Y - volatile unsigned char *cur_buf_ptr = NULL;9 F8 C( R: x& I: T" G) \* c7 k+ R
- volatile unsigned char *data_ready_ptr = NULL;
J) N5 t- T! s, n
2 c* G8 S- P" G+ Y
6 B) f/ ?+ Q3 a( t; q3 R3 t3 y( g5 ]- / ]# Y( a, X6 p
- //定义读数据等待队列头,IO阻塞/ w+ K* E0 m4 X" ~8 m
- DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);' j4 z' W3 [. k4 I7 T E# v
4 D1 a) o5 o9 M- //定义原子变量
1 o4 b6 {. k, d M6 O8 ]% Q7 Y - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备/ y B; H1 S0 b
- ) z: H; j0 R! b4 N- b9 h
# `& w. _/ V6 C2 O- //定义设备类
- Y, S) s! k* f3 M K0 Q - static struct class *protocol_class;
! _6 D. n5 p" p* z: ]& ^( { - struct cdev *protocol_cdev;
' u$ d$ D( E4 ?4 A - dev_t protocol_dev_no;
- l5 @; q) [, e6 D& Q. ~ - + P7 @1 M0 o" V n
- /*定义tasklet和声明底半部函数并关联*/# X" C' h- R' G" t' @2 D
- void read_data_tasklet(unsigned long);0 i+ m" A1 T6 |
- # z$ Q$ A' _6 O. H) f! o1 ~ ?1 N0 M
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);" w+ G B, v, `. z# ^8 V7 i
- //将CHIPINT0_tasklet与read_data绑定,传入参数0
) r- }2 s1 E7 K! }. R' U
3 z5 q+ Y+ y% }+ A- /*中断处理底半部, 拷贝内存*/
- `" x2 q8 i }( n4 r9 L9 n* h) R - void read_data(unsigned long a)
/ r( w9 _/ M' f# K9 { - {3 g7 S' p% v! C& X
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1
+ J% H, m# u, |+ @# ~( ` - {
; T, d; i% U/ z; v, a B - read_quest = 0;
- n" p4 S W/ U. d+ |* Y6 l - wake_up_interruptible(&wait_queue_head);//唤醒读等待队列2 }3 f8 F& z: q% V- }
- }
- }% } x- `0 S! g - $ _5 l- H+ R0 a, H& B) X
- }& Z# h: B# G5 R3 D& y2 S8 x( P
6 s7 `' w0 J/ F0 |3 M3 j" Z- /*中断处理顶半部*/
! b. m0 A7 w) O - irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)
3 i: S3 X5 a9 A; | - {: J( w# A4 s, w! |. f+ v
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样- Z7 Y1 u; P- F" i
- volatile Buffer_Type *next_read;
3 Z* p I" ~ o; L - //如果DSP数据已经ready
- L9 @& W8 S! s5 o! o" x( V9 ?' d - if(*(res_buff.cur_buffer->data_ready) == 1)8 `& j8 _$ v9 w- Z% O8 \
- {. Y/ }& N: ^# z3 U/ y: Q- r
- if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer& y4 `! T) V! _. G+ v& |: ] d
- {! Y% I$ [+ c/ f" [2 S9 |
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer
8 z6 r/ e0 |. ]; q; n. L: ` - //printk(KERN_ALERT"read ping\n");- j4 r$ T* V* L$ Q. G) Q, i5 z
- }. w% X, b7 h. e/ K
- else
+ |% w8 O2 U: l- w; ?. n - {8 Y, R3 l9 u0 [( m. a0 o/ }
- next_read = &res_buff.ping_buffer;//下一次中断读ping buffer- I. l$ C9 k. ?1 @4 w3 B% \" T
- //printk(KERN_ALERT"read pong\n");$ `1 ^" |1 b* `
- }
: m1 s' B$ r# i! r! w - *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer8 E+ ^6 ~0 Y2 I" E9 P: v
- //将数据插入链队列
$ z9 S( O( j' ~6 I/ Q - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);
5 u6 u5 U7 s# h9 Y$ m! d T - //标识位都重置( i7 k8 x( e( a" N; Y& Z
- *(res_buff.cur_buffer->data_ready) = 0;7 x8 d# n4 V& T3 `% q5 x
- *(res_buff.cur_buffer->data_size) = 0;* O( T% f% M+ Z0 D; b
- res_buff.cur_buffer = next_read;" x B; V/ h% h3 u* {7 \
- }
4 Y5 q7 g- j5 W t6 y3 W& B - //清楚中断标识
1 s8 `6 U+ V6 W1 w/ I+ \ - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status' ^2 F& s0 F9 y* l
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部 . x. t& C2 w. a# q# L: k9 j
! b- Z1 Q" W6 v1 O, H" M
z; Z1 j$ n% p+ K M) p- return IRQ_HANDLED;
# @& ~6 x5 v8 A
" w6 N9 Q: C7 ]- ]3 y( c2 B- }' r% I3 t6 ~) M
4 \* U0 {7 e: F8 c5 k- //文件打开函数0 T, o4 L o1 o7 {
- static int protocol_open(struct inode *inode, struct file *file)
- _+ J) x' W! _ Z+ g - {
: N9 R9 H7 ?8 a' n9 z1 J2 H+ l - int result = 0;
% _7 L, W) v) [ - if(!atomic_dec_and_test(&dev_available))" u" A3 d" P& y' ]! a, e
- {
* g, c2 I+ S8 C" t4 Z; c& b - atomic_inc(&dev_available);; \3 H, ]3 Y* M$ ^( ]; z1 Z
- return -EBUSY;//设备已经被打开) [3 D* U+ O; M2 L+ z1 U
- }1 g4 @$ n8 Q2 ~& ~# L
- printk (KERN_ALERT "\nprotrol driver open\n");+ E; r( }" M7 @( f
- return 0;
/ c' D0 A* y7 I+ ~7 K! a: q8 o - }, U# N) L( `9 X5 C/ s2 R
- 0 u1 }: V( K1 D
- //文件释放函数9 \5 A/ u( k4 a
- static int protocol_release(struct inode *inode, struct file *filp)
; h) B1 ^" c4 } - {7 b0 I& r, R" V6 z8 c
- atomic_inc(&dev_available);//释放设备,原子变量加15 `* f3 l' z: n1 E6 v8 y* B# d
- printk (KERN_ALERT "device released\n");
( q; ~$ y. S2 ] x, _6 b* y - return 0;2 }/ L; G8 H$ x
- }. L+ C X& w, m* E6 d8 W& _
3 B! J" j* U8 T6 W9 q& m' R- //文件读函数
% }2 c0 o2 U Y$ b# K - static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset): D0 x% t- ]: B+ n
- {
# L9 s( K/ }. I* P5 o# }9 K - int ret = 0;- L. }& U: B( |2 s/ w1 w
- //定义等待队列
7 A: u! ]6 i4 o8 g6 y& s - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列
5 ?3 |6 T8 A- q# y" ?7 g - add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
- O7 y. F' R; R& | - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
5 d5 \2 J2 p: M. @. } - {
4 ]( N8 ?& o3 Q0 f- _0 T - //printk(KERN_ALERT"\nbuffer no data\n");8 V8 ^% }3 T) B( O8 s3 k6 e
- //如果是非阻塞方式读取,则直接跳出
6 K; A" S' Z6 c) D* X+ l: d& n - if(filp->f_flags & O_NONBLOCK)
" [6 K" j* f l; a" j - {+ k" [7 Q+ q% f+ J$ j5 G: G; C8 u
- ret = -EAGAIN;
7 \% ~, n: F2 q- _* Y - goto out;( T/ U1 G# O4 f% |( }
- }0 @" J" h% |/ n6 l5 k
- //阻塞当前进程,放弃cpu资源3 {1 \7 k1 ?9 ^* v; Y1 ?0 z: K9 x. p
- read_quest = 1;
0 t' x( z) K$ E3 q2 r& P - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠7 y' S7 g! a6 J+ d6 V
- schedule();//调度其他进程运行8 C- a3 T3 I/ \
- if(signal_pending(current))0 H: @3 h/ ]# H0 m, U) v- g
- {
. y4 m ^0 h5 I: b9 F# E# N - //如果是因为信号被唤醒,则返回到系统调用之前的地方
s X: m/ \( | - ret = -ERESTARTSYS;
- |- \; u/ i. A9 h - goto out;
. [' \3 u, G' R - }. y4 w+ }$ p9 }
- }
* c8 R+ B$ Y1 x1 `1 N, q+ }" B' q$ g - //将数据拷贝到用户空间- A: o' \0 g% {
- ret = k_linkQueue_getData(&queue, dst);
5 ]2 B; G: X6 y! s3 I, C5 T - if(ret == 0)+ g3 K r% ~# |3 v! ~* T; L& O
- {) T& O0 S; o3 @- O- n' N& Z
- //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);3 J3 {" q/ q1 R0 r, ]7 {4 p
- }2 G& N% \+ B5 ]8 b. @
- out:5 F0 ^9 Z/ G& @0 D
- remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列4 B8 c, D4 U4 j* v4 }; b. d& F; P
- set_current_state(TASK_RUNNING);//设置当前进程为运行状态
& {7 t- c! l) C' a7 z - return ret;
' I+ f5 ^" v- l+ }1 s' ~8 O - }0 c* O+ P* l# w
- / A( {, ?: F5 j+ t
- 7 Z1 Y5 v3 c/ ?$ z0 x- f7 \
- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)) D9 t! g9 A9 i: h8 F8 B$ f+ ^5 O
- {
3 x7 A4 R, |; ]+ Y! u3 T - return 0;
5 F3 Z7 J8 |9 P# ` - }
3 g! r8 `7 V, `# m l! I" G - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行3 K1 z+ M a3 S# i$ T& l. R
- open()、release()、ioctl()协同调用时被调用*// ?( t( C+ O S ]( g* Z, ~# y
- static const struct file_operations protocol_fops =
/ B3 F9 A# o: u& s4 M% O - {
/ F/ m: m: K4 `6 n. W. k8 T O: Y3 @ - .owner = THIS_MODULE,
) _% t7 E0 { b - .open = protocol_open,/ I; n- t8 L G1 u# h- m N
- .release = protocol_release,# S( Z5 ~: H" v4 z! b5 m" e
- .read = protocol_read,# W. x0 B. v2 |0 I
- // .write = protocol_write,' V0 F2 S+ C* I/ k; L: H
- .unlocked_ioctl=protocol_ioctl,
& |% `/ `( w8 y2 s* t: E; D - };) B5 b) j7 D, P* P7 B- B, `4 @
* K) {3 O4 Q1 c ^- /*设备驱动模块加载函数*/$ T* [4 B2 S4 B8 A! ?; ^) c" g5 J
- int __init protocol_init(void)
u; L) ]* Z8 H; [4 r: n - {
8 h1 _$ Z% W1 H! N1 ]$ A+ |! q - int ret = 0;
) `8 |: M% A; e; z3 p - int result = 0;
1 q. k0 f, J8 J, W+ z8 m - //申请注册设备号(动态)
. V u* H P9 ]3 v - ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME);
1 M: o" f; G. j. B5 a - if(ret < 0)( [# b1 h0 i) r8 A; _* F0 l3 z
- {
; m% R9 d8 H7 f2 G% R q3 q8 Q - printk(KERN_EMERG "alloc_chrdev_region failed\n");, N2 O) T* F1 v7 U+ H3 Z/ t$ G7 B; Q
- return 0;3 F. M( c B: ], r+ ?7 D/ W1 T
- }$ u3 |9 |: _/ \& f1 {8 h
- //分配cdev, V2 v- V& R! D1 h1 [4 V! _1 F7 f
- protocol_cdev = cdev_alloc();
% P8 s; E& x- n - if(protocol_cdev == NULL)
; W. j% }% n3 ?2 Y9 n3 r, ` - {
' w( m4 p# G- S- @% E - printk(KERN_EMERG "Cannot alloc cdev\n");
2 F$ U3 j2 r o) ~& F/ I. W - return 0;
# O# m& P1 W" \7 d - }# D1 S. H. m R; t) x9 s
- //初始化cdev$ t* L5 ^# h C
- cdev_init(protocol_cdev,&protocol_fops);3 @% V! F; f- W/ E. F0 [. T8 h5 \
- protocol_cdev->owner=THIS_MODULE;
$ B6 ]' }0 F4 c - //注册cdev
' X. t- k# X$ @! n* G2 s - cdev_add(protocol_cdev, protocol_dev_no, 1); % h! S; R! b8 `' L3 \' i
- //创建一个类
4 Q1 S, |1 U/ |- E- }6 G - protocol_class = class_create(THIS_MODULE, DEVICE_NAME);( r% B# S$ d# v# {3 l8 }/ `
- //创建设备节点
) h# y8 \1 v# P - device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);# M0 ^: x# N) a7 L
- ! F; d: e7 t2 s T9 g
- - M2 [, b c6 _1 o1 r$ p* Y
- //申请链式循环队列作为缓冲区DSP数据帧的缓冲区4 T5 F+ O& J: N x8 P. ~7 r
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区
+ o/ J- c4 X$ }8 { - , i( E, i1 k9 G4 e9 w' u
- //映射ARM的核间通讯寄存器9 w% O1 M/ B1 a& e
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);. T. T+ R! i6 F) d( b6 L
- R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);
" [0 O- r" n( h1 \6 B - //将物理地址映射到内核空间
3 Y( @: Z4 s$ ?$ r w5 E - mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);
# A+ A' M& L |0 ]" Q5 D( H - //共享内存初始化
& s* u: e2 \: x% C# Y - SHM_ARM_Init((unsigned char *)mem_base);
- q$ M& S5 [6 H. z* d8 U2 a% L - /*申请中断*/; J( `, t5 {4 T* s0 W1 A+ v
1 [5 T+ K4 n, T- t- W! _- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);" M% ]3 R S! E2 n3 o$ [: i
- if(result != 0)
4 y4 P3 d9 b- S6 U) D- [ - {) d/ z; q8 s1 K @( A
- if(result == -EINVAL)
8 N( v7 V9 h8 b, m1 X! \! a! m9 Q - {7 o6 ~3 x( z, l% x% F( p0 K% P
- printk(KERN_ALERT "irq request err:-EINVAL\n");4 {! W+ y% F" i7 _
- }! J `1 s* R+ r- R) y$ n$ [( a
- else if(result == -EBUSY)1 |# \1 M. ^* u
- {. a2 f; ^' f! N& L8 {& y N2 D
- printk(KERN_ALERT "irq request err:--EBUSY\n");* u- \. n/ z" [
- }
( l, U. F6 H$ h7 F8 Q- I - else2 Z6 L# [3 ^+ s2 @; k1 H9 F
- {
4 Q* n# t# t B2 Y4 J$ M - printk(KERN_ALERT "irq request err: unknown\n");
% J$ o8 f- x* ^( q - }5 J# L6 F+ ?/ n: ^9 R1 v
- return result;
6 E; @/ }% P. v1 q4 x6 p+ r( M- N - }5 X# H/ ]6 r2 N
- return 0;1 q# g, N( M- r: @6 J2 c0 e* g' e
- }
' m i! L/ T9 {' m
3 s k, g- w& v" E& f- /*设备驱动模块卸载函数*/
+ v1 ]! U |! t/ T$ k2 X - void __exit protocol_exit(void)
# X6 d: e9 {& w9 _9 V - {
/ g5 M4 `" j) X6 I' l4 U - /*释放中断*/8 S2 b$ A; H, X' o+ |/ M% o0 m
- free_irq(IRQ_DA8XX_CHIPINT0, NULL);
( q x* O, w) R2 Q - //释放帧缓冲的内存
) ]" ~: Z, f$ ^8 U2 u7 r2 L& B - k_linkQueue_release(&queue);3 ~7 d6 a. K! h, l# B* f
- //释放寄存器映射
# T& ~/ W8 |- m5 N% D! j( ^1 ? - iounmap(R_CHIPSIG); N2 `% U! |3 | c8 L0 U
- iounmap(R_CHIPSIG_CLR);( _. g7 N: O0 U5 L5 E6 I6 Q( M1 Z
- cdev_del(protocol_cdev); //删除cdev
0 m+ w4 j$ D- g# {' m - unregister_chrdev_region(protocol_dev_no, 1); //注销设备号
) I% I( @" |. V" G C6 q% f# Z - device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
3 _6 D8 I1 b! H* [ - class_destroy(protocol_class); //销毁设备类
( I( G1 I7 W2 h7 a! F - printk(KERN_ALERT "exit success\n");$ W' w' p0 K+ h0 |. d* O0 V
- 0 e. I! D- l; h( S
- }5 I% s# Q% V/ o; a
- //驱动其他部分省略
复制代码 4 q* D( A" N9 k- S
( p# ~3 i. @8 f2 l# x5 { w: T |