本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑 # ]( g, W4 N8 R7 k) E
0 I) g( k, q/ s项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略. w5 g' O" O! a& f1 n$ V
' g4 s/ \1 g" Q* \8 I3 S/ V- //引入其他模块函数和变量4 j( O) ]/ }* L+ h9 t
- extern Ping_Pong_Buffer res_buff; a7 Y3 c. O2 r) S+ s+ t
' s9 `7 P/ V0 x+ _# N+ O- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列
: ~4 M; G0 `" a4 {3 L$ ]/ j' @ - extern void k_linkQueue_release(linkQueue *queue);//释放链队列- e. U7 y! \, V9 K/ L5 F. i0 [5 q
- extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据) H: ^: h( p4 j }' G5 D
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据1 L) F: H9 F2 ~2 B
3 a# x6 ]* m7 D' n& D* a0 |5 u- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化( P) i- f* F) U2 W9 w" t( K
" r+ Z1 F5 a& n' g/ h- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1
% Y1 }5 J6 _( P5 X+ X4 @- q6 i% D3 P - //设置主从设备号
y' q# u2 h) ?3 R( G" {: L. } - #define PROTOCOL_MAJOR 1% d$ i! H4 Y I$ I4 d i. }
- #define PROTOCOL_MINOR 0" w+ R# I) o! Z. J8 `, q
- , C& k8 ?0 ^5 {6 P2 p
' H% y" Z* y! `* c- x- / h+ u3 g; {+ M3 a+ u3 N( P; U- d
- //定义设备驱动的名字或设备节点的名字
% O+ n2 T& C7 X d9 S - #define DEVICE_NAME "protocol_driver"
) Y2 W% G7 z- m+ F7 {
' _ F L; X* X: n1 J. e+ v1 W5 T" j- 4 K7 U# J: b& V3 p- Y7 g
- //定义全局的循环队列作为数据缓冲区" ~ L3 h4 c7 `
- k_linkQueue queue;7 [5 ?" O. R6 c/ V5 _
$ W$ Q9 q9 L; Q' E. o; p6 y* x- //寄存器地址映射全局变量7 v4 {4 g8 K5 r) I4 I! a
- unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器$ j4 k5 U, G# f4 H
- unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器: y. w, ?& t$ V
- 6 j4 n; o# B) E q6 K# U$ t
- //物理内存映射全局变量+ Y+ Z, o& w6 R+ W4 f
- volatile void *mem_base = NULL;; f0 T/ o- ?# d# M5 h
- volatile unsigned char *cur_buf_ptr = NULL;: {6 D# M4 ]( h" l; I! [: ^# `- z
- volatile unsigned char *data_ready_ptr = NULL;
! x, X9 o- e6 u, H& V) ?5 o
) S- Z' [2 O1 C$ k3 K
1 f2 q4 _4 D# O3 d( \- @
: M( a7 B- m- r- //定义读数据等待队列头,IO阻塞
% o# L1 ?; u. i) m7 Q - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);& K- l) j- h2 N7 C# C" o
: b9 _" l" O7 V$ } A- //定义原子变量1 \# J( B9 L# V, v# }
- static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备( U1 L: B/ V) f
: h& S% |. B: f' p1 g, q6 p7 Q/ g- , y' v) b9 K3 r
- //定义设备类
8 u K, A7 J) W5 ]0 Y - static struct class *protocol_class;6 C+ \: [; `2 V1 S( @2 r
- struct cdev *protocol_cdev;
$ y0 V6 s4 d% x, x3 u - dev_t protocol_dev_no;) l2 a$ I7 d# k) q
0 q1 u; f3 C& V6 R0 W- /*定义tasklet和声明底半部函数并关联*/$ l$ ]4 {0 R) e" X1 U" ~
- void read_data_tasklet(unsigned long);
. F* x3 y# Z1 T& Q& G - " P' E# P0 Z' F
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
( N v1 k9 M* B- `' {1 b1 P - //将CHIPINT0_tasklet与read_data绑定,传入参数0
4 L8 v$ Y ?+ ?, u$ |% s
, f b% C3 n0 G# E3 ]- /*中断处理底半部, 拷贝内存*/( }, J6 Z2 a* a% Z8 N3 I
- void read_data(unsigned long a)
3 q. x% [- u; q2 N- O5 T6 Z - {
( C: ~* R1 ]% @6 w - if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1
" B- g3 K: U. M6 A - {8 w. E% p/ Y* W: ~5 ^) B' x: q& g
- read_quest = 0;
/ K z% L, g" L1 L* v - wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
: {' Q. X# A# _& x7 c2 h0 A - } h9 F' Z1 X+ T. W R
- ' M; c* y/ r# U% v0 ]- v
- }
1 S$ |# s. U E5 H3 ]$ S9 e - ' ?- D9 W/ p* m6 z
- /*中断处理顶半部*/4 r) n9 t6 C1 d, p0 o
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)
& e$ s& G2 H& k0 J6 |$ Y' s - {
% s, E) `6 a# d7 q/ q. _ - //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样3 S* U* K! D0 R. F; ~9 |( e7 a1 k
- volatile Buffer_Type *next_read;
1 N& f% P2 V4 l - //如果DSP数据已经ready
$ W1 [- r* v8 [: Q& @ - if(*(res_buff.cur_buffer->data_ready) == 1)
+ U' y3 Y O) V- K1 ?. g2 p1 ~ - {- |1 G6 Y5 }- J# ]/ Y2 ~
- if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer
0 P' n M* Y8 N7 o* h" s - {( W' @& ~3 p; ?
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer
8 L6 p* H: L+ X- t P7 A - //printk(KERN_ALERT"read ping\n");0 @ y6 f5 ], q
- }4 j( w l1 n2 C: ]' h9 A' K% o/ a
- else
% J7 y1 t0 M* D7 C, H' k - {
/ Q( n' Z9 @7 z2 u( p - next_read = &res_buff.ping_buffer;//下一次中断读ping buffer N2 E7 l6 u/ }! x o
- //printk(KERN_ALERT"read pong\n");
; w; B" M2 ]% `/ a0 b' | - }
6 ?) O! m; X4 f1 [ - *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer
4 t) d- m: n: i, [ - //将数据插入链队列& T1 b. g: {# ]5 H' L3 x5 |# a% \
- k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);/ N" z0 q0 G2 }% |# t8 R D* T4 s
- //标识位都重置- E1 `0 \' k, W: s
- *(res_buff.cur_buffer->data_ready) = 0;
4 s( Z; [% I$ B( |/ S: U - *(res_buff.cur_buffer->data_size) = 0;+ L' T" q/ \6 F+ [; i
- res_buff.cur_buffer = next_read;8 ]; \/ e$ G' x/ z
- }
& G2 D# j3 m4 J; Q - //清楚中断标识
7 u8 H3 y/ m2 n ^' n( {: q - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status0 G* P4 L4 d" i% \8 S/ M
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部 $ o3 b5 }: ?5 E* j% ?5 P1 ?& D
( w, X6 n% e p7 C, H# P$ C8 A
2 d. K4 R2 l% W4 m6 ^- return IRQ_HANDLED;9 [ J R/ V9 k; P
. Z( m/ z& R1 J( E- }! o- c) ^1 o3 E$ O, m2 M1 w
; D( x% f5 u, s6 Y! `; [/ G" Q- //文件打开函数5 T' \ Y$ M- t
- static int protocol_open(struct inode *inode, struct file *file)
, T H6 y6 s; {8 X$ u - {
7 |& q# G9 ?' i4 M0 { - int result = 0;
0 U9 r& q/ n4 Y' H6 C - if(!atomic_dec_and_test(&dev_available))6 V; O; V t! k( |7 T
- {0 _9 p/ h5 s" I e# M( l
- atomic_inc(&dev_available);
* ?2 t4 V8 U% K) m2 N - return -EBUSY;//设备已经被打开
( D) P& R) B% a+ h) _/ i+ {: H - }
; Z0 g+ A; M/ ^3 ]( ]/ v6 i! @ - printk (KERN_ALERT "\nprotrol driver open\n");
0 v9 z: `+ B* q- [0 }+ }7 } - return 0;. b0 v4 t2 G E4 P
- }
6 t$ ?/ B i3 \% h; y - 8 p$ b, E5 a1 ]
- //文件释放函数* X; q2 o8 s% c8 j
- static int protocol_release(struct inode *inode, struct file *filp)
0 ~" r. Y* m# ^ - {6 j3 I" c. c& P7 I( V6 C0 O' n
- atomic_inc(&dev_available);//释放设备,原子变量加1
" e, A/ w8 S% A( S - printk (KERN_ALERT "device released\n");
+ V/ Y: L4 Y" b9 u - return 0;# E! R' e; I) Q% k9 T
- }
: W( q0 y4 e2 ~! y( b
+ m0 x' Y1 z7 l; X0 |9 T7 N6 y- //文件读函数
8 J4 L4 ]$ L$ R0 |% o, Y - static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)/ ^( T1 U9 {" C9 w R/ f z
- {
6 ?6 v3 F+ w. ?3 \; ~ - int ret = 0; ?$ m- J5 L& l2 |2 I3 s
- //定义等待队列& G& o$ L, P/ X- c3 T8 z9 o4 j
- DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列! E f4 G0 B* V \$ V
- add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列 f- ^7 p) S# ^# D
- if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
1 l) y9 u* ?; K/ S2 T1 V7 s# I( f - {
6 o! @) V8 X/ F - //printk(KERN_ALERT"\nbuffer no data\n");
9 n+ h; F( v) u2 D3 d9 j - //如果是非阻塞方式读取,则直接跳出- M$ q3 p5 |: @8 K
- if(filp->f_flags & O_NONBLOCK)
/ d9 n* I9 |/ k - {1 d) ?. {; K7 v3 l, C
- ret = -EAGAIN;
( J; R" e, u( q$ `0 u M2 b6 O - goto out;7 u0 ^' a* s( X$ u+ X* {
- }
! x6 h& C2 I' f u" T9 z - //阻塞当前进程,放弃cpu资源
% r8 ?* l- R R- M3 \$ M6 b - read_quest = 1;) G0 i; M7 }0 F$ N
- __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠5 b M1 T! u9 G, y4 b0 `- f+ `
- schedule();//调度其他进程运行3 Q" @& j) X8 g
- if(signal_pending(current)): o$ I* t7 f1 M s) O: J( K
- {3 ~9 U: L$ W: S ^+ k) e
- //如果是因为信号被唤醒,则返回到系统调用之前的地方/ k: U# g) r Z/ B l7 w
- ret = -ERESTARTSYS;3 ?+ M1 c4 g' q1 {
- goto out;: ^( ?( \3 u9 V6 {, ^3 T# g
- }
. z9 M8 E7 f0 w: V - }- w$ R [2 O( r. G2 a0 W2 G% G
- //将数据拷贝到用户空间7 V2 f! b) A4 `! a% J- e
- ret = k_linkQueue_getData(&queue, dst);
0 {' k. |+ r/ B4 m9 s - if(ret == 0)& f0 }: b9 ^" W: H
- {
@4 |1 ]# \" U5 E - //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
, K T# s7 [! t g - }
5 J \1 p+ D1 W7 U- u, ?+ _ - out:5 ^9 t2 F& U# `- ~3 L" M2 J
- remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列! H5 g- }/ i# k2 e
- set_current_state(TASK_RUNNING);//设置当前进程为运行状态 J/ [. R7 o; G& @4 f$ x% E
- return ret;1 f6 h s# I- n3 }
- }. l8 d, d6 j0 l8 r& N5 K
- $ t( z/ f2 S0 a; m. u) C: V! k
. [9 ~; T, n! v" c- j- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)
: ~# [3 ^; w" c - {, i9 k0 J9 x$ t3 @( |
- return 0;
! m* j$ E3 }' i, [# \ - }
# T; e: H% U0 { - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行
) |! P3 X' @) s( x - open()、release()、ioctl()协同调用时被调用*/
; ~3 `2 A' V$ V+ Q - static const struct file_operations protocol_fops =6 N) |: C, d a7 M; }+ ~
- {
, l( [( B% q% d. ?* Q9 Z - .owner = THIS_MODULE,
' C, g, x( E2 d. Y - .open = protocol_open,3 }; W6 O+ O6 R$ r4 d+ N8 C
- .release = protocol_release,
* U! @, w1 ]7 f$ B3 @$ {8 e - .read = protocol_read,, w' ~8 B, v% y1 ^* h
- // .write = protocol_write,3 i, F( `. C6 |& i! l1 z8 n( j
- .unlocked_ioctl=protocol_ioctl,4 G* p6 `: ^. z# j+ t6 K
- };. X% Q0 X, k9 K9 z
' I. `$ ?) S$ _+ ]- /*设备驱动模块加载函数*/2 H0 |8 G+ Y- J5 s
- int __init protocol_init(void)! Y1 b% d& H$ @- F% X1 x. U
- {
' G* v/ N9 E7 w6 I5 O1 G - int ret = 0;( q- a& b" t( n. l. S
- int result = 0;
" I- v8 ^5 L* D( g; ? - //申请注册设备号(动态)
. _/ E0 ]& f# ]: A# T. V/ D - ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); % h6 W( p( o8 s; C8 E8 m! |3 `
- if(ret < 0)2 _7 b( G; x0 D; w1 [+ h0 n) j
- {
& V8 o6 h" V9 W) A) l; u+ Z - printk(KERN_EMERG "alloc_chrdev_region failed\n");
! w# S a/ W% | - return 0;$ z/ g) m" S2 C1 E. B
- }4 S% c+ F0 ?. i/ L; x U3 p
- //分配cdev
. s* x4 o& F# z6 J& x: `% z: i - protocol_cdev = cdev_alloc();$ ?3 ~& m5 R1 Z) O- g" R8 L
- if(protocol_cdev == NULL)
4 f4 x1 }1 w2 i/ t' T& J2 O7 j - {
8 L, N8 ]$ v% z# g& T3 C s) \ - printk(KERN_EMERG "Cannot alloc cdev\n");8 S1 O, d# S) H4 K2 t. ?: O* s
- return 0;# ?6 }% a6 _+ N: v+ `
- }& a2 t6 l1 ]& I( o4 E7 ^
- //初始化cdev
! A/ k L+ z% N1 h O6 c - cdev_init(protocol_cdev,&protocol_fops);# I( T0 ?7 i+ A5 D# t. T/ J
- protocol_cdev->owner=THIS_MODULE;6 g3 S. F8 w8 L& I3 @- H
- //注册cdev( k! m8 E/ u! o! ?0 R
- cdev_add(protocol_cdev, protocol_dev_no, 1); * b9 Y, H" E2 u( G
- //创建一个类
3 o$ J) y, E1 J4 i( ]" y+ U - protocol_class = class_create(THIS_MODULE, DEVICE_NAME);6 }2 [, L" D6 `6 i$ @" R+ x. z
- //创建设备节点
0 v) l. \1 y: H6 v a* \ - device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);
2 f b% E8 X, h2 r - l4 g/ D4 W% y- j
-
" a& k) V7 ^! R - //申请链式循环队列作为缓冲区DSP数据帧的缓冲区
* m# y4 G" r& R - k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区
/ X3 n1 f( V0 |0 s' J( j6 ~/ G
4 M# X+ I5 ^# H- //映射ARM的核间通讯寄存器" G/ i% s6 j$ _7 H
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);/ _# J8 F* {! t' {
- R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);
# D$ n2 A0 \; R4 G- \3 x! Z& {1 Q - //将物理地址映射到内核空间
& j' _0 y; p: }. V4 E - mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);5 n" A) `1 r- K/ s' p8 L
- //共享内存初始化
' U" B" c( \0 k) p' n/ x - SHM_ARM_Init((unsigned char *)mem_base);
$ g1 g& M% Y! s# v" n8 C( ?! c' e( r - /*申请中断*/+ V, _$ k4 m+ j) [7 U+ x0 m9 M
- 4 j: u: b4 Q; Q5 E6 j( D
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);$ t4 h' w! a" n9 R. W- I+ ]+ A
- if(result != 0)( R1 O3 P9 N9 o; B1 D
- {
. K4 t( D% }# x6 E; `8 x - if(result == -EINVAL)
B$ \) `2 \ D- m* x" ?5 ` - {# j# R7 j# U/ u. m" h ~1 m
- printk(KERN_ALERT "irq request err:-EINVAL\n");
6 m% `9 [1 {& J4 r( m- d - }. b0 M9 Z2 y; }% p0 A! S
- else if(result == -EBUSY)
/ z& H: ^- \$ N4 X. U: ~ - {5 ~3 T* H9 X3 q' w3 g
- printk(KERN_ALERT "irq request err:--EBUSY\n");
9 p) D2 L( X) g+ o9 ~6 \ - }
! l$ m) S: ?" u$ D) f B - else
6 J/ s* P' }+ u - {
, a, b+ z7 a9 t5 r. N - printk(KERN_ALERT "irq request err: unknown\n");5 ?* k* c# x: }3 f+ w
- }9 Z ` I, d! d- r* I% D( R, ~
- return result;
0 m- p2 R! b9 r- c6 J* O$ D. Y0 i - }/ o) y1 K) l4 x- Z) V! X* ` r
- return 0;
- O/ E& \! G, P+ R# _7 V - }
5 w8 a' s: O. C6 w( r* `0 N: K$ I
`( I. C6 ~ |/ Y0 h" _# A) z- /*设备驱动模块卸载函数*/
, X" e7 k) E9 m7 O - void __exit protocol_exit(void)
' k; c% ?8 {' u0 ` - { B5 |( j" Q' \0 d
- /*释放中断*/
8 t/ `" Y: Q: w- C2 X& W# q2 M - free_irq(IRQ_DA8XX_CHIPINT0, NULL);
2 u5 z6 d3 L. k3 Z, h( I - //释放帧缓冲的内存9 @; w: I' j2 K0 q
- k_linkQueue_release(&queue);" f% i( i/ P7 E+ J
- //释放寄存器映射
, W4 m' p9 Z6 `( H& r - iounmap(R_CHIPSIG);. \" }3 T5 A8 \1 f6 I
- iounmap(R_CHIPSIG_CLR);
, ?5 W) C$ G0 U - cdev_del(protocol_cdev); //删除cdev
( h9 u$ g% T4 ?: @/ @* u - unregister_chrdev_region(protocol_dev_no, 1); //注销设备号+ N; {9 g! K2 u
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
0 t' \2 h* l9 s, O! E+ D - class_destroy(protocol_class); //销毁设备类5 u4 B' F/ v8 i) `5 L9 q
- printk(KERN_ALERT "exit success\n");
! i$ P! @. p/ W1 K0 c/ \ - / Q n8 D+ S7 D
- }% K! i' X$ d o$ l8 s3 T) {' D& @
- //驱动其他部分省略
复制代码
7 v' K! A0 n# f% K. B0 y, d! Q r( b5 s q4 t) K4 |
|