本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑 2 u" h+ i8 ^1 f5 w7 W8 Z
" y' L! k! }; l; Y项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略
* t5 |4 p3 P5 }+ s% i% N - 7 O; I. R2 C! r2 U
- //引入其他模块函数和变量& r3 Z9 w. X# x. g" Y
- extern Ping_Pong_Buffer res_buff;1 {8 R' n+ q, Q. m
- " L0 q' Z5 @: m& O' _
- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列
6 |, \' O5 o; \. K/ C0 o5 \ - extern void k_linkQueue_release(linkQueue *queue);//释放链队列% r( x* j) A/ G
- extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据2 S5 ]/ p& s/ s; n5 J# z
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据
! E+ c( ] I# F1 ]$ k% v+ O" p
L5 P* F( ^; @- Z2 U2 y7 P- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化
6 y5 [' q4 k9 M - ' q" Y& x3 b# O1 R$ l, s0 c! r6 ~6 E
- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1
; F8 ]- q. T$ X5 r6 s - //设置主从设备号, B5 m( H! z9 C9 S2 M9 p
- #define PROTOCOL_MAJOR 1' o$ d' U6 Q7 \- e2 J1 y6 Z0 Z- k
- #define PROTOCOL_MINOR 0
6 T/ L6 h' d& f - - E2 f% N5 g( }# U) |& L
9 }' J4 ?6 E$ s) a$ A# V6 q K: B
G4 k0 B" t& z6 K. N! a- //定义设备驱动的名字或设备节点的名字8 E5 z' D( R+ y% k6 l2 ~0 |1 m
- #define DEVICE_NAME "protocol_driver"
9 j$ S6 T5 T. R, T" T
' u( Y; w! g8 @( {- 4 }4 T. F1 u; \3 I. h
- //定义全局的循环队列作为数据缓冲区! U- l; o4 |+ k' Y
- k_linkQueue queue;8 G4 c# r) b6 |- ?
; _; R' g6 a8 H( N: e- h; @* x- //寄存器地址映射全局变量# K! C8 C3 g0 O$ ~0 q
- unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器
3 G# `' c/ K$ J - unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器( |0 H3 F. I) z& _9 D) w
9 _# x; v q& U! g- //物理内存映射全局变量
' q9 T: D3 n& |6 I( k2 [ - volatile void *mem_base = NULL;/ I7 a# ^5 U8 r+ S
- volatile unsigned char *cur_buf_ptr = NULL;
. m" m( r; e" m# u - volatile unsigned char *data_ready_ptr = NULL;0 s( A$ }- K* u# e* }+ h
- 5 e# A! o( X( L% g, H+ \% \
8 u5 K1 H/ _: H& i0 {- ) } |7 J2 X, c: Z
- //定义读数据等待队列头,IO阻塞
9 t" x& n0 G- w1 J7 n - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);
. w. T. I' v2 z, Q6 Q' F* f+ q
( q3 d1 @: `; M) L" t' d- //定义原子变量
, N. ]: ?+ u S+ b3 S$ | - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备
& N+ i, V( ? v: }8 F1 c' Y7 r - 7 Q5 M& N( |6 W% t4 d M/ i
- 4 _; C- s$ s" c5 ^( n% T4 o
- //定义设备类
8 b6 l+ v7 ^7 K$ [/ c" f - static struct class *protocol_class;3 U% W! Q1 K) d5 x+ ?# I2 n' C
- struct cdev *protocol_cdev;
) F$ [1 R4 R7 K z - dev_t protocol_dev_no;( o% O! S( ?: \! z4 K4 }0 n3 q7 L& ]
- 4 ~6 E! G1 F5 \/ k& T
- /*定义tasklet和声明底半部函数并关联*/6 f7 A/ j# j$ b0 ?! `
- void read_data_tasklet(unsigned long);
* N f5 B0 H, T' v7 e) s/ k
}& T4 W2 n! p: G# a- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);& ]: {) \! n. N% k5 f4 n6 S
- //将CHIPINT0_tasklet与read_data绑定,传入参数0+ D7 m7 S- d, p2 m5 a
- 3 `5 G6 A* S5 j% r' ?. F
- /*中断处理底半部, 拷贝内存*/4 X) V7 C' F$ d8 i3 I! A
- void read_data(unsigned long a)* k( p0 @8 n8 I6 G# i2 |# r
- {9 Z* s8 J3 k, R M3 N- J5 P* q
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1
0 T- M0 M/ p, Y, x0 \. e9 L6 L/ K - {
# N1 K1 B/ g s5 Z# Q( y- @( Z0 h - read_quest = 0;
! p+ P' h' @2 }9 T% n9 Z5 {8 ? - wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
7 k" a( T( _- j - }8 h, I x( c& s* [
" M- ^( b# K& Z2 j4 w- }3 J1 `4 v, z) b
- 7 D! L; n1 ^4 K' V- n2 P, k
- /*中断处理顶半部*/
, |3 U, X3 Q9 h6 F J; U, c - irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)+ d& N" {) d8 o; Z! `# ` J
- {9 T) @: g" x0 G. Q8 h: D
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样 ?8 Z- t u9 u6 a K
- volatile Buffer_Type *next_read;4 I% ], O0 E4 ^+ [: z$ F
- //如果DSP数据已经ready4 Y$ S! q5 I5 \' Z. ], v
- if(*(res_buff.cur_buffer->data_ready) == 1)
6 U3 r4 E/ ^+ N; K6 |# p - {
* D8 ?$ o& h" N/ j' U8 V - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer, r, c% Q$ n$ _2 ]& u% m5 O/ _7 S$ {' B
- {3 A2 H( ^: O' e; t
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer, Z/ r. J( B j" m/ k4 `
- //printk(KERN_ALERT"read ping\n");
0 Z" N: m! c, f4 w' { W p7 G, v- _ V - }
/ a2 g) B* z+ E s2 E) ?* H - else
# W5 c E+ q1 S3 p% g9 [2 h - {
" ?# j- {) I$ X9 o4 |$ e/ W* w - next_read = &res_buff.ping_buffer;//下一次中断读ping buffer
4 q' S) ^9 e5 W/ r/ g - //printk(KERN_ALERT"read pong\n");# D, F G r }. p/ L' w, x+ \! T
- }/ f4 Y+ @# W1 O3 U) A
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer
8 |% X1 h: I, @& k. q1 k4 R* O$ `! f - //将数据插入链队列/ a: X! L, v1 @- D2 R8 j
- k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);9 W. H% O7 S& ~; M
- //标识位都重置
0 J6 E+ V8 g% b+ u3 i" Q - *(res_buff.cur_buffer->data_ready) = 0; e) A/ W2 y6 V1 z. L
- *(res_buff.cur_buffer->data_size) = 0;- y" o, q7 `/ m
- res_buff.cur_buffer = next_read;2 o$ n9 t$ C' o( j/ M \4 x
- }
/ U5 u1 ?( h. g: Z8 w7 o1 h4 e - //清楚中断标识
+ {! d. g! F; Z1 \6 E3 _( D - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status
& `) B5 W1 ]& {9 ~0 ]0 _" o, N- i - tasklet_schedule(&CHIPINT0_tasklet);//调度底半部
$ @5 @% C( Y$ o$ R/ f& T - 4 |5 F& X1 W& Q- x1 T% P
/ {8 C1 [; t" {5 N* d- return IRQ_HANDLED;
6 u0 ~% k) [5 f. u% D. C) S5 k
2 g2 B$ @/ X0 d6 ~- s4 n1 Q" J( w- }. L9 e- \8 k. Q3 ?# }
. b8 u0 ^0 X; E/ @3 [# ^- //文件打开函数5 N! X8 M' Z/ [2 C7 e% l
- static int protocol_open(struct inode *inode, struct file *file)8 N" u& o1 h$ w9 f) c3 H
- {
& \$ |8 a: w) x' b& j - int result = 0;7 \0 }; u% y4 G6 X+ }8 I
- if(!atomic_dec_and_test(&dev_available))
' P3 ]8 ?5 ]$ m d9 z# }+ { - {3 I2 q. [7 f/ i$ c; E
- atomic_inc(&dev_available);5 U; E6 j2 H! W! y" {
- return -EBUSY;//设备已经被打开
5 q x# \+ U5 [4 Z) D; l4 H2 J% S* c - }
7 R+ ?4 M7 g/ w$ K& S! T - printk (KERN_ALERT "\nprotrol driver open\n");$ t2 y3 S% P; U( R3 [8 V/ `
- return 0;
- X0 ~% _9 d+ `6 W, `. J - }7 Z8 G/ ^# k! {: o
# r$ A0 X0 k- o- //文件释放函数
2 G; z( N0 o) E1 \5 b6 C6 l - static int protocol_release(struct inode *inode, struct file *filp)
- @8 j' |2 B; q5 h" R7 z" D- v7 x - {
@2 k9 L1 H, {. Y& z6 C* b2 ]% @ - atomic_inc(&dev_available);//释放设备,原子变量加1
6 b" K; Q; i" w: d; O( \: s7 I( t - printk (KERN_ALERT "device released\n");
7 v5 N c3 Z; Y$ g - return 0;2 F$ W0 S- m: W! ?9 c( h( z8 G1 I4 j
- }: D$ o$ I f5 L1 L* i- t% d
- $ X- O# Q6 h. r' k5 n/ B* D$ ?( V
- //文件读函数& b% Q7 q" t5 `7 `" f6 a
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)
* l N5 ?7 q1 q2 M" C* O3 X. L - {! C9 t- E v/ w2 c0 j" V! w4 f& N
- int ret = 0; A) V. k+ j* q) D$ I4 y
- //定义等待队列
/ M) T0 _, d) w( c7 q( G1 ~0 Y) G$ l - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列2 J6 t7 X) o- D6 G2 O3 E1 F6 I2 w% A
- add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列9 X( |! v' R/ U/ L
- if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
9 q" F& s! e6 n. G8 p8 z+ ? - {
0 e2 [/ c$ `4 h% R - //printk(KERN_ALERT"\nbuffer no data\n");* @5 ^7 L7 \9 [" [1 ~4 V( ~
- //如果是非阻塞方式读取,则直接跳出
+ R" _2 b5 M* w) [ - if(filp->f_flags & O_NONBLOCK)& i* z: y3 K1 x2 v5 e* ?$ Y5 X
- {
4 K2 e; d+ A6 h& ]& ~' H - ret = -EAGAIN;
+ s) R/ c6 n+ f! d) A7 | - goto out;3 E* h* { @6 Y% s
- }
# g( m. \6 |4 B1 p9 D' n& d6 f/ K8 D - //阻塞当前进程,放弃cpu资源6 F3 ~; q' r: `* {1 s; d
- read_quest = 1;
) M1 G! g* `7 Q6 W# C$ I1 s" z - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠& O* k$ x2 F3 y( t
- schedule();//调度其他进程运行
% V# z4 U6 o- t$ z) y' Z6 g - if(signal_pending(current))& K$ Y8 s# K4 {% _# P+ Q
- {3 q; M8 c+ k3 A7 W
- //如果是因为信号被唤醒,则返回到系统调用之前的地方% I* L# d7 n. o/ Q5 U( \
- ret = -ERESTARTSYS;
3 X& X' d% w+ ]9 V* v4 l: D5 x - goto out;+ }, ]0 |; F+ b# Y0 G h% f/ y
- }# v& o9 |# v5 ~, }; v
- }1 ]" m' H! r9 O+ g8 q
- //将数据拷贝到用户空间' |3 E1 [; p6 N+ ^( ]7 I4 x
- ret = k_linkQueue_getData(&queue, dst);. U2 v R/ _' {9 ^5 D1 [) h0 a
- if(ret == 0)
( m: @7 J9 E1 h$ m+ Q( M4 x" |- h - {
/ x2 z6 H! R/ w) ` - //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);( Q, G1 W1 v. t0 D7 ~+ l& V
- }
* u& Q6 g; G+ \/ ?9 P6 j& y3 \ - out:
' x* i* ?/ |- i - remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列) Q) B$ g0 @5 F$ y+ g
- set_current_state(TASK_RUNNING);//设置当前进程为运行状态' \8 B# T6 ]0 N6 v% q) m) ]; N7 n
- return ret;1 n$ B9 j/ c! {0 B5 E- G
- }
0 Y6 P8 u+ ^" k" f: C
+ {6 L0 [( l; R5 a
/ i$ R2 M% l5 C. T. L! E- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)0 k4 u* W0 f# E
- {- l3 {1 o) | A3 y' T2 G2 B6 F
- return 0;
/ l6 d: h2 N: N( @ - }
* g1 H5 o' n8 x1 l0 M- z - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行( q9 X1 V. a# J" z
- open()、release()、ioctl()协同调用时被调用*/
0 x9 ?6 }. z1 R, W' t - static const struct file_operations protocol_fops =
, ~& i9 U- ]5 g0 {% K1 O - {
, f1 ?0 I7 S1 G: w& x4 G - .owner = THIS_MODULE,' R6 `. ]3 _- q% r% C2 C8 N/ p. G; U
- .open = protocol_open,
# A' g) ^& ]; h3 i - .release = protocol_release,* t, J% u9 K* t W! s6 G
- .read = protocol_read, [# [: d) m1 m. @
- // .write = protocol_write,# _, `- V4 y" E3 r
- .unlocked_ioctl=protocol_ioctl,/ L% D7 B3 D7 c- a
- };( h0 e# T) e w5 _, o( S; j
- 2 @& G7 z$ P* `/ A" B( M- `/ K
- /*设备驱动模块加载函数*/2 q) e6 T" c" Q, F1 N$ ~
- int __init protocol_init(void)# E% h& q$ W& i: f# x
- {
2 H+ _8 G8 o& L6 V( [ - int ret = 0;* k7 ^6 ^( t3 Y k6 [) ?
- int result = 0;
% D7 B) \1 r, S* H- |; t( `3 ]3 V - //申请注册设备号(动态)
# c* Y. i! j4 M - ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); 5 X( h, O9 M2 j
- if(ret < 0)
7 n$ ~* D8 u2 \+ X9 m4 Z% G - {
/ Z6 O* I3 h8 A5 S; j$ \ m- R$ k - printk(KERN_EMERG "alloc_chrdev_region failed\n");
7 e8 r) p- j# ~0 ?( w - return 0;2 k2 M$ |0 X. P" S4 X
- }
* I- h" R7 ?$ e6 l: U" ?8 _5 q - //分配cdev, _4 F! w/ D e& J1 s
- protocol_cdev = cdev_alloc();
: _# w7 o8 C: w n( K4 F8 b - if(protocol_cdev == NULL)2 {; [$ F: C0 ?! e. V( v! P: ?
- {1 `6 V3 H" g7 _$ E4 I
- printk(KERN_EMERG "Cannot alloc cdev\n");
$ L' @( } y9 r& O- ~ - return 0;/ X3 q* X! W3 K2 }, ?
- }& }, J! t) o* ^( r1 U
- //初始化cdev; Z* ?3 h/ T! P( F8 v
- cdev_init(protocol_cdev,&protocol_fops);5 B) j. g# ^, a
- protocol_cdev->owner=THIS_MODULE;
6 S& g9 P) _ h2 F, G, \7 i - //注册cdev+ R, n* ]* b: b: r% X2 z
- cdev_add(protocol_cdev, protocol_dev_no, 1);
$ y' s' w: m& ^ - //创建一个类
* m- R' e) d& c - protocol_class = class_create(THIS_MODULE, DEVICE_NAME);
9 h _& `8 J. y5 ^ - //创建设备节点
t4 F" ~8 [, C: v9 V$ d9 s9 @ - device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);/ J% @! \3 c$ L& T6 n9 t6 p
- ; x: |) Q9 h5 r, g" f2 K" E2 k' O/ O
- " E+ ~0 c- J e1 b# X6 B% n9 `8 A
- //申请链式循环队列作为缓冲区DSP数据帧的缓冲区& d4 o% w4 a) G! i/ m7 I
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区( T3 k& ?# y& L; E/ l2 y
- ! M b( k" T* J9 Q, O
- //映射ARM的核间通讯寄存器
+ P+ K' ?) e5 e! w - R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
+ W" c8 y" ^0 S5 f7 X - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);4 c% u+ w. R1 }
- //将物理地址映射到内核空间% g( Z( a( S8 s
- mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);
) D4 O, J9 M9 T* w" [" ?6 | - //共享内存初始化
' A, j5 W1 b( Y. A! b/ E1 Y( C* c - SHM_ARM_Init((unsigned char *)mem_base);
/ y* H1 W( A+ i - /*申请中断*/: \1 r) u, n+ Z) o8 I# X. i
- 5 T- O* o2 \; l. X9 j% t0 V
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);( q4 C k$ w4 C2 G d
- if(result != 0)1 G5 _! x4 w8 Z2 G/ E9 r) l
- {
) K! q! I; ]1 S$ T' s/ G4 r - if(result == -EINVAL)
% p1 r4 a/ O& ^2 \ - {
4 f% P( n+ |* H& T J - printk(KERN_ALERT "irq request err:-EINVAL\n");3 S5 P( r- Y! W
- }
. B2 w# v5 O. i) x# N6 W - else if(result == -EBUSY)* q) c2 ^. ~# z: v7 g
- {$ Y2 |8 n$ L, Z9 y9 q1 E# ~ K
- printk(KERN_ALERT "irq request err:--EBUSY\n");
5 a1 {9 L1 f" {$ M& D - }
F/ A. [3 Y m - else
0 U- J+ O; f1 I8 ]$ I" W# K - {
& @- ]6 }3 Z/ r( u O - printk(KERN_ALERT "irq request err: unknown\n");
6 d/ v% h! P& w$ \. h L. ? - }; m( _1 z" U, k; b* w
- return result;
, i# K5 L g y9 P' Q/ q - }
3 I! h% c: _0 Z - return 0;- I4 @- h, o9 u' M$ z
- }
/ B& E8 z% e2 k% R - ) `1 d& n5 q( h' B1 H
- /*设备驱动模块卸载函数*/, m: n5 Y1 G X- Y* D$ I
- void __exit protocol_exit(void), y( k: y$ H) t+ _6 M
- {
( U" c# h4 a1 @ - /*释放中断*/2 p9 h4 b" K; s$ t* a
- free_irq(IRQ_DA8XX_CHIPINT0, NULL);9 [3 @# ]$ v2 P7 \% K2 ~/ r
- //释放帧缓冲的内存
) v: C6 p) g1 @ - k_linkQueue_release(&queue);$ e! Y6 z- f0 I ~0 |; D
- //释放寄存器映射
O" f# C( ~. w; F7 J - iounmap(R_CHIPSIG);
0 J/ k0 d1 P! i. T0 t - iounmap(R_CHIPSIG_CLR);
2 `; [; v8 S% x3 | - cdev_del(protocol_cdev); //删除cdev
! m& `7 `1 _0 @0 j: Z. U - unregister_chrdev_region(protocol_dev_no, 1); //注销设备号- a. Y& U }) ?
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
: G+ N% D* B% M7 u/ Z - class_destroy(protocol_class); //销毁设备类
2 {7 b" x b& Q! ~% d. g& b - printk(KERN_ALERT "exit success\n");* M* V E4 d3 m( x( w! y9 |
& U% M$ Y$ Y8 z9 w- }. ?/ k o9 u) o1 }7 l4 Y" N
- //驱动其他部分省略
复制代码 / r$ _ z$ t( ]- `4 |6 P
+ Q1 t4 f" s5 [4 I2 p& B
|