本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑 / P% F# Z7 r: ?& [
) Y: a8 `8 Q _, H/ r5 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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略" l6 H3 x9 U5 ]) G+ m; E
- ( {4 ~" P# Y! r
- //引入其他模块函数和变量6 A1 `3 @) N9 w/ V% U* M* b
- extern Ping_Pong_Buffer res_buff;
; _: M- t. x; p1 s. k
. A( I5 Q# f1 i- J7 j/ v" E- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列$ E9 f4 I0 h6 d+ `5 E
- extern void k_linkQueue_release(linkQueue *queue);//释放链队列
) P( w+ a0 H1 d: K0 K0 v - extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据5 [, g, @1 l- |/ T, s
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据
$ V% l/ T7 _- ]& B
# z% V, x3 I: S/ X6 O. [" B; y- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化
" i, A8 f5 w' B0 c( _ - 7 i/ c: I. a5 D- ?7 s( l5 S
- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1
+ V0 w# b# U3 f' k0 @' [; M - //设置主从设备号
g0 a" ^: b; Q2 j @ - #define PROTOCOL_MAJOR 1- [. ]* j4 e; ]2 H6 d1 T
- #define PROTOCOL_MINOR 0
: M) v. Q# i( C2 t3 f
+ \, C; q4 K! E- 7 f0 ?7 R4 N9 N$ a4 p
- 8 X* B n* b* h8 |+ k! o
- //定义设备驱动的名字或设备节点的名字
/ G9 m2 j# Q* k - #define DEVICE_NAME "protocol_driver": x! ~5 N; J# G& I
9 n1 S* @! M5 {2 B! g. ]/ D- 4 X+ D/ C% E! h
- //定义全局的循环队列作为数据缓冲区. m" V" K5 u& B1 j
- k_linkQueue queue;
+ z% t: L9 }+ \- O, C
4 H' S8 x) A2 v' Y9 i- //寄存器地址映射全局变量) f# `; F+ s0 U! U; a+ |
- unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器
2 S$ r3 ?% N# G% d) C* { - unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器9 h( F# e' b9 B1 F7 v
7 }" J6 L( Z$ p! X N: c& g- //物理内存映射全局变量; T5 n" k6 p! o$ z
- volatile void *mem_base = NULL;8 a2 D0 C8 n3 b; C% w" R: }
- volatile unsigned char *cur_buf_ptr = NULL;
6 `# ~' P6 c+ a% H" W - volatile unsigned char *data_ready_ptr = NULL;" v& t; C( S f0 F5 ]
- ) O4 k( d* O# B, B( C0 T
- , k# l! y( [1 D4 W4 ~
6 N: Q ]1 i% e- //定义读数据等待队列头,IO阻塞
2 B8 ~6 }8 P) m5 L( X& ]# _ - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);5 k5 ^. d+ v7 U$ e7 ?
' k5 a. N1 v9 [) x! }- //定义原子变量
0 b7 m E2 X( l$ I- L - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备
' g: L0 S( K) ^6 n. O- I; T8 e - 3 R3 F+ j5 U# l: v3 k V: E) r" [
( E/ z* s0 b2 T6 ~7 t' d- //定义设备类
$ F a9 Q+ p3 b6 i: V5 G6 a - static struct class *protocol_class;
& K1 y- c8 W& |4 p K0 C7 D - struct cdev *protocol_cdev;/ x* ^, u. o+ U0 [
- dev_t protocol_dev_no;$ `: a0 p9 s& y& l) Q
( {4 D! `4 i/ U7 c. ^$ H5 c# r, T5 Z- /*定义tasklet和声明底半部函数并关联*/7 I6 R+ U7 k) B% b- ]* E
- void read_data_tasklet(unsigned long);
8 Z/ B; f* |$ Q! E/ q5 a1 _
# i2 l4 r! b2 w& G7 S) z! p- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
# ? F" x; C7 q- {) ` - //将CHIPINT0_tasklet与read_data绑定,传入参数0
, ]+ A0 w- R1 P - 9 J' T: W" A( l2 H% n
- /*中断处理底半部, 拷贝内存*/# \$ G: _/ ]/ Y- {
- void read_data(unsigned long a). I0 O& l) w' I2 I6 c& B
- {2 d/ }1 k3 f3 _. s. m! U- L$ u3 L+ \
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1
% H: n7 E7 n4 G& I6 n- r - {
6 G5 n. O+ y2 } M3 C& E) M1 O - read_quest = 0;
# t6 k \: b. w" A8 R - wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
9 N5 i: g" Z- x - }
/ R, b7 |( p3 Y - % u/ p' B' J& y# f; h: I/ M* o+ |! k
- }, \( d+ C, Z. b% Z/ S" e% N: I
0 m3 w: O' f+ O/ ?$ x- b$ j- /*中断处理顶半部*/1 A8 x" \6 u" @; p+ e# h8 M+ O
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)# u' ~0 _; \) E, K6 B& t" P$ {" j
- {6 L9 N8 V4 F" p+ r$ M: ]
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样- b2 R- T F6 T3 o# m" J& K$ }
- volatile Buffer_Type *next_read;
4 E5 H; ~' V$ ^% H7 k, J+ V4 E1 | - //如果DSP数据已经ready0 F A+ o0 t" f: Y! W
- if(*(res_buff.cur_buffer->data_ready) == 1)4 ?0 C8 S% u; h+ h; g
- {
7 L! W% Y# h$ T. b' F( a - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer
- Z( l$ l$ G( L: }- H3 n) R - {
4 b9 [5 x/ v# m* w) G6 R - next_read = &res_buff.pong_buffer;//下一次中断读pong buffer6 C3 F5 K1 Z- U( T2 M+ y
- //printk(KERN_ALERT"read ping\n");
6 i0 z! O8 j% u+ m7 s/ ^ - }
! W" t- s$ Q3 x" u& x4 {) r - else) M; ?% v3 D$ `# t; m
- { w6 X" E4 z" \/ G* L2 D8 s% {
- next_read = &res_buff.ping_buffer;//下一次中断读ping buffer, ^, j' v* j* ~/ o( J: n
- //printk(KERN_ALERT"read pong\n");; c9 T& G$ C5 x
- }4 ^+ n5 `) o( l6 I" Z; B
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer4 c; G. v. W, t" k7 d
- //将数据插入链队列
; A0 X C+ z) \' v* Y6 V3 g - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);! V$ Q$ z3 |( @ L1 R" ?3 O
- //标识位都重置4 d1 t8 A3 O T$ V) V. H
- *(res_buff.cur_buffer->data_ready) = 0;, f% n2 Z {' Q: M; A# V' E, C4 F
- *(res_buff.cur_buffer->data_size) = 0;% z9 L+ j" T4 l/ M/ D0 D* ?" n
- res_buff.cur_buffer = next_read;
* G' h- F$ j! ^1 Z# w c* p - }
& _1 _, `5 Y; L6 i - //清楚中断标识
/ o" y6 R6 W# l$ a8 L2 [! g - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status
" S( `' h; l+ {# c1 d - tasklet_schedule(&CHIPINT0_tasklet);//调度底半部 8 T4 `8 M9 C% \5 Y% o% z
- & ?. {; Q: f' \6 Q
* I$ E3 h# p: Z. p# q2 b- s- return IRQ_HANDLED;
" C$ v+ A- i, H y' b5 k9 n4 B/ C
$ Z- C6 }' p+ Q$ a- }$ e0 {; y5 {! C* Z% i9 |
0 [2 T5 P) Y' z% A( R4 U. Z9 F- //文件打开函数6 @) V% M2 x% z; L( W. f
- static int protocol_open(struct inode *inode, struct file *file)
$ \9 i" X- P. K1 k" C; b: O - {
; M! y( ]" J' C6 a- | P" ~! [ - int result = 0;0 M; L' V0 b( w' q; |" q6 ~
- if(!atomic_dec_and_test(&dev_available))0 B ~8 `& e* b7 S
- {) g, v( W. n5 U; a9 |0 m% M
- atomic_inc(&dev_available);6 _0 x5 J" Y, r
- return -EBUSY;//设备已经被打开6 l& U M* p. p0 J( ^8 T7 A; ~& p; P
- }
# n- V: J' T& l, e - printk (KERN_ALERT "\nprotrol driver open\n");
& c0 {1 X, F& |. E: j - return 0;
* _( ?; ?- H x. r$ C - }
) c8 v% q- U) X$ c
7 J9 n# {6 l* j+ i( N- //文件释放函数0 N% @" ~/ B0 F* F% i/ I
- static int protocol_release(struct inode *inode, struct file *filp)
8 ^* i: c; C4 l# C, }$ _: k7 J) X - {
! c4 s$ z/ F3 _: h$ J o - atomic_inc(&dev_available);//释放设备,原子变量加1
8 c) d- Y* }9 s) Q/ |) w! u - printk (KERN_ALERT "device released\n");
6 W- n8 w, V# h5 A* P8 s* @8 [* u - return 0;3 t3 d; D3 j$ n, X
- }
/ z5 v' L% M K3 ?3 s
1 \( I' |( [5 {; j" N) H* X G+ Z- //文件读函数
. z, w: i. m8 f' n6 M9 O8 ^: M7 u - static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)
: i' c. i1 y; s7 j* _ - {: e% P; \6 {9 z) R! D- {
- int ret = 0;8 D( M2 R h- j& S( k/ u
- //定义等待队列( N- X" o0 K0 T7 H5 r
- DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列
7 H' h- G! U, Z$ ?; j# L) v - add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
- m4 a5 [1 E3 y3 b2 m; V8 w - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
: F, m" n* c4 V) U2 g - {7 n8 ~, d8 m( e6 I! _
- //printk(KERN_ALERT"\nbuffer no data\n");8 j" F& {% k" b6 q% C& D k0 U
- //如果是非阻塞方式读取,则直接跳出2 x9 W! }0 F: V- w( K6 t) K
- if(filp->f_flags & O_NONBLOCK)2 x3 {/ Q. l7 @8 ~* N, f }: U5 b
- {
, [% @9 o2 U0 S* N( y0 R - ret = -EAGAIN;2 g$ i( n" m, ?1 E! d3 R: |
- goto out;
- }* T! q# x3 q* T6 ?- q3 n - }7 ]- j# |. Z3 B/ {/ W% y/ {& w
- //阻塞当前进程,放弃cpu资源4 P2 l; ]4 g- p4 f, p
- read_quest = 1; Q( {6 q/ D! P j, X2 O: ^$ w
- __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠
0 x) k1 n, j1 F- _ - schedule();//调度其他进程运行- r$ s9 v$ o+ S$ [
- if(signal_pending(current))6 a( {# C5 ~' \5 S# ?6 X$ y
- {9 \* y( P6 Q$ I# d# @0 W
- //如果是因为信号被唤醒,则返回到系统调用之前的地方
6 E- V2 K3 X8 a- Y6 ~' g% ?' a - ret = -ERESTARTSYS;7 e* x/ |# R7 x. w8 F* U/ j
- goto out; B# a; V, X. g3 t% G+ M( O
- }
6 G3 |2 J8 a7 v: W; x - }. G' L; w) `3 ^
- //将数据拷贝到用户空间1 V7 e4 f/ q0 a; U z3 a* R$ F
- ret = k_linkQueue_getData(&queue, dst);5 x5 h7 X2 c9 y, [% I m/ k
- if(ret == 0)
9 t7 R4 |! n+ S8 H - {: i; E% u- v6 f; z& Q4 k
- //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);3 V$ \* Z$ j8 b& k, a. W
- }
- D, e3 P$ J! [8 W5 Q - out:
& y2 ?3 q+ S( s$ p N - remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列
& P5 y, ~4 @4 x/ r( f/ Z - set_current_state(TASK_RUNNING);//设置当前进程为运行状态8 d/ Q0 a3 l U0 j/ J& i
- return ret;9 A" Z1 H9 F& }9 ?, [8 A) G
- }+ `. g( }! E: |; X# i! ?% H
- : g% a6 t% B4 o! j! A! P
% t3 R' x3 R0 V; S- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)* J% S$ g1 h: ?4 h
- {
& l" R* ^ l2 N% j - return 0;
0 b0 T8 L4 e7 j- y - }8 H0 s# }5 i0 w9 n8 F
- /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行( X5 c Z- T* d& g
- open()、release()、ioctl()协同调用时被调用*/4 K0 _4 B3 \ F$ M
- static const struct file_operations protocol_fops =
7 ~+ k/ j2 M3 |/ `- d3 i y - {
) B- |' R; u U9 Y4 A - .owner = THIS_MODULE,
6 s. s1 g7 b& }( W0 \& A - .open = protocol_open,
7 f5 d6 }* L. V* q- B' s7 r - .release = protocol_release,
9 I: q! t9 X) C b5 }' C - .read = protocol_read,
" p: F/ s* A) ?. d7 b7 r h - // .write = protocol_write,
, o: S |, p" t* t7 ^6 n - .unlocked_ioctl=protocol_ioctl,
3 \+ o7 P5 n* @/ k3 P/ ?$ \0 u - };
! ^5 q1 s3 R" e' d3 r L. n9 f% Q - * U% v6 d2 p1 D5 i
- /*设备驱动模块加载函数*/! \4 M! B5 _; ^2 X2 R/ q5 r
- int __init protocol_init(void)
1 F. f: b& z0 x1 I6 |+ P% F/ f - {8 N7 w! K/ g P3 t) t& O5 g2 f
- int ret = 0;3 B6 B1 O5 u3 I
- int result = 0;
- n6 E9 J8 A/ V% m5 Z, L - //申请注册设备号(动态)
: O) W9 X7 C! A8 H4 L5 y - ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); - p' L# Q4 Z) V( e. I7 b
- if(ret < 0)
& o8 g' H* q. O8 L) E$ d1 J$ q! X n - {
7 g$ Z" I, C# J8 k" d - printk(KERN_EMERG "alloc_chrdev_region failed\n");, s: M3 U ~( o- x9 }
- return 0;
2 H6 S" G6 Z9 [; b - }( _" W& m- T) K$ n) ~" ?
- //分配cdev
+ \) J4 ?, i- r h6 x - protocol_cdev = cdev_alloc();
( p) D4 y/ v+ w$ Z9 f - if(protocol_cdev == NULL)
9 m: t0 T0 E7 C+ |5 n F+ ~ - {: ], d( E, P! B! @. l; b; Z# D% x
- printk(KERN_EMERG "Cannot alloc cdev\n");- S4 t1 A& Q7 Q+ t3 J0 ^. H
- return 0;7 l$ ~7 }! f. _) L3 X4 M
- }
& I% M) H R9 x/ R! V0 m6 I3 P" S - //初始化cdev% h5 N( v- Y& u( w+ V1 d0 Z% S
- cdev_init(protocol_cdev,&protocol_fops);
6 [( R4 o2 r3 ~! s! X+ } - protocol_cdev->owner=THIS_MODULE;
/ W* F% r, a9 n. l - //注册cdev" q* }& @ s* D$ p/ a
- cdev_add(protocol_cdev, protocol_dev_no, 1);
) O* l4 t1 g+ N* u% F6 X/ m - //创建一个类
1 r8 T5 {; A" c5 x# I+ F( i; z# Z - protocol_class = class_create(THIS_MODULE, DEVICE_NAME);7 N1 r1 Z9 Y+ [6 ^+ Y
- //创建设备节点' P7 i1 ^$ e8 S1 }& T V4 v
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);+ b+ o$ Y0 H9 D1 ` A. T
- : g& s+ @2 V1 p, z/ N: b
- 1 \% X' i3 \$ ]9 L2 F* {9 Q
- //申请链式循环队列作为缓冲区DSP数据帧的缓冲区2 a/ D7 ^! w) r4 y+ a
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区
5 ^* A) ~# U7 x2 o8 ^ - 9 `9 ]# a1 e: t# W3 V# D$ x6 w- T( r
- //映射ARM的核间通讯寄存器
: i9 H5 X* ^# \2 R! u% ^ - R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
; e. }1 y, I8 o" y3 r6 q8 K6 D9 u - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);
b) A2 v# R3 ? - //将物理地址映射到内核空间$ H4 i5 L# b/ B W& @( J
- mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);& B6 e3 C, P {3 v
- //共享内存初始化
: F- c/ X$ `0 F( m/ I - SHM_ARM_Init((unsigned char *)mem_base);
% L+ ]( W/ G3 B; h0 ` - /*申请中断*/0 ~. G3 Z8 Z6 W3 V
9 v0 ?; {9 Z% x1 Y- V/ D- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);$ Q. G, D' D2 G$ o d! t, Q4 _1 \0 V% ]
- if(result != 0)
6 {: i% H, s. D - {
X0 U% f# q3 X9 z# h - if(result == -EINVAL)
! E& ^: D; L; E: m; Q! y - {
$ x J$ U+ f5 ^0 k( A8 f- J - printk(KERN_ALERT "irq request err:-EINVAL\n");4 a! b$ p5 z& ]/ l7 D8 ^# m
- }2 @* j" k# Q5 v$ g$ B
- else if(result == -EBUSY)
* l' h2 D; Z+ {+ Y9 x5 D - {
2 Z5 @! k8 j/ H9 a - printk(KERN_ALERT "irq request err:--EBUSY\n");+ @. _ F& G# z- ~/ |
- }
. L0 I7 H! b% P - else- K# p, k' J" P
- {0 v8 I* z% l( d* V* D' A, G" |, z
- printk(KERN_ALERT "irq request err: unknown\n");- p2 n7 W1 A0 D5 v
- }
* I A, G) T P% s( l1 J2 h - return result;
# l4 J* e/ c2 I3 f/ h/ h3 w% a - }
% ^- _/ E0 a: s) r) ?1 c% t - return 0;
' K- T7 s7 C2 L C) s - }, r% X' R! z: Z
- ' U: s+ Z( [: M. L
- /*设备驱动模块卸载函数*/ v2 Z7 \5 ^7 Q, l: _
- void __exit protocol_exit(void)
: J# f! p8 H+ z1 @1 E) v - {
1 B! I$ C! A) y2 ?/ E: K0 w1 Y- E - /*释放中断*/
) q2 j( F) I( W. p. O" B% N - free_irq(IRQ_DA8XX_CHIPINT0, NULL);
; k8 k2 S+ y$ z4 A9 B - //释放帧缓冲的内存' o3 ^4 d% l2 P6 R6 x/ ]- E
- k_linkQueue_release(&queue);
% h7 _3 ?( c: ?/ k! B* m - //释放寄存器映射8 K( i; C2 u1 |: x
- iounmap(R_CHIPSIG);
( D6 O' N, W( x8 Z$ L3 L - iounmap(R_CHIPSIG_CLR);$ w: y: }# I/ y! U9 J
- cdev_del(protocol_cdev); //删除cdev; z8 P$ Q! [" W" e( y# w
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号
9 D- q9 |- S3 o+ E' B; ?2 K$ b - device_destroy(protocol_class, protocol_dev_no); //销毁设备节点( n% u9 I$ b2 c4 |% K
- class_destroy(protocol_class); //销毁设备类 J7 a' X# n% v2 N) o
- printk(KERN_ALERT "exit success\n");" C6 q: W* ^: i; h* F& J
+ V( m5 Z8 v) f3 L) d' z1 q" U, c- }: X5 d4 D& M& x9 p4 B0 b, a* u2 M
- //驱动其他部分省略
复制代码 " @- J* l0 F. L+ y
- `+ B- K9 Y6 j, _$ `8 X& L6 n
|