本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑 / o. m0 J6 E0 V5 n
9 Z x9 S8 B! Z# Z项目要求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 x1 h# X6 I7 G: z3 ~: e/ x+ Y
H, a2 m1 F' c2 E) I3 D' ]- //引入其他模块函数和变量
/ k& N: F% Q: l+ V x+ u - extern Ping_Pong_Buffer res_buff;. v0 o# F9 o: s+ U
- + ^" u/ w5 D: I' f2 f, H Z y
- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列% j. P `3 m ^+ Q
- extern void k_linkQueue_release(linkQueue *queue);//释放链队列9 o% F- {3 B! w3 n" _
- extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据2 O: o. m& S6 j2 V6 ~
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据
( i4 [/ ^( B4 ^. B: m$ T& o
0 S7 q A* i2 y# I- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化2 c% n6 S3 K& h4 i0 a' A7 u
( \4 K7 v% V" e- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1
+ I$ ^$ M' @; K g _ - //设置主从设备号6 N; f# J! T5 B5 T3 f S) t1 M' Z
- #define PROTOCOL_MAJOR 1* C7 \; }8 C2 a/ k; c9 H& e/ q$ D+ }
- #define PROTOCOL_MINOR 0# k1 \: o9 D; F* \+ e# X7 X% L
- 6 [: K/ \2 V" e @0 h
# p7 ^5 v! A8 K2 a- " J$ A. Y8 W e
- //定义设备驱动的名字或设备节点的名字2 o5 S9 @ V! `. v2 X( p
- #define DEVICE_NAME "protocol_driver"* w# W9 K5 F1 ?! R4 j% x
) B5 C5 V' o, U3 U* }
) W* E9 J* Q1 K1 o4 |. j- //定义全局的循环队列作为数据缓冲区
4 a @. X: p0 p+ R - k_linkQueue queue;
9 e+ p: z" t: U# S7 \ - 1 H0 @% U4 m4 t4 j# B
- //寄存器地址映射全局变量
9 K2 I; G+ v! T: C7 U3 u7 r - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器- w6 K9 U( ]' `5 ~& a/ |
- unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器+ `9 R) \" ?4 p1 a
- & F L( ]) C& n' x) a6 Y
- //物理内存映射全局变量; \+ n/ x" s" C
- volatile void *mem_base = NULL;; X% m. v- N8 _7 i& p8 e
- volatile unsigned char *cur_buf_ptr = NULL;' h' g! c) q/ [( u. k' I$ e2 u
- volatile unsigned char *data_ready_ptr = NULL;
( w3 m2 R7 ^$ G5 Z
0 q0 }5 w$ [" b& P( m
2 J3 H* F8 V9 w- R3 A6 X$ i+ T9 N3 R
" g1 R( Z9 ~' h! l- //定义读数据等待队列头,IO阻塞
; @+ s. r, W' A/ ]8 D4 w, X0 F - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);. L0 w1 L+ n& Q
- l& q" D& ]5 }; Q) G) d
- //定义原子变量4 d* D4 T( d) o2 ]( S/ p7 x
- static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备
) ~: @9 l8 W5 l# @. O- o0 O! n
4 }. a% E+ k. s0 k0 T5 c
8 n- N$ s/ X4 N1 Q* f+ ]+ w" z- //定义设备类
( G1 j& c5 @- O - static struct class *protocol_class;
) S [7 G6 O2 f5 E1 V4 q - struct cdev *protocol_cdev;
. n8 `8 }8 |5 b% K: A% h - dev_t protocol_dev_no;: y1 o$ ~' t: k( u7 R0 }2 N3 e
% i3 J0 Y) b% h- /*定义tasklet和声明底半部函数并关联*/
) L) Y- j. B- v - void read_data_tasklet(unsigned long);
3 f- ~, l" e- G9 P+ I
6 n9 F. s! M* z- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
C) s. `1 ~. B/ C - //将CHIPINT0_tasklet与read_data绑定,传入参数0! |: I ]# v, Q2 r. \# m x$ e; O) J
- # J0 d0 z2 D0 d3 Z& l6 S' c
- /*中断处理底半部, 拷贝内存*/- C8 Y3 `- V- f- D+ v
- void read_data(unsigned long a)
4 N" I; e6 M' C4 e" U - {% A' L, I! R# S' G4 N# ?
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为18 t9 Y0 o) x* ~8 ?1 n- }
- {7 }$ P5 u) V+ Z6 G2 Q3 R& _
- read_quest = 0;- J7 F3 H2 B: x1 q% K) r6 `
- wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
0 D- ~4 P. ]9 R* D$ e4 L+ c6 I - }
2 U6 m/ W6 u( G( L) q - / c {# z/ G, [$ m) ^
- }
/ A2 x) q' {7 S' Y' X+ _; } - 4 e$ ~ e/ Q$ B- ?, J# ?- a
- /*中断处理顶半部*/
0 J* [( r/ }% l- r - irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)2 i& b" Y6 \6 A9 P
- {2 C6 ?6 @) X& q( E8 ~0 W6 |" ?
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
5 b3 k& J/ s/ H8 T/ h0 ^: O - volatile Buffer_Type *next_read;% P3 {5 T" F: g! ?1 |0 ?
- //如果DSP数据已经ready
* f0 k0 `3 e' q8 f6 y - if(*(res_buff.cur_buffer->data_ready) == 1)
$ v, ^% z1 h- E; d - {
' [9 b6 e) Z/ j/ r5 Z* C - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer
7 j6 x, _5 |: ]" u; D; T" j0 u - {$ w- y; e5 M9 o3 _5 {
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer
; E1 ^ W0 K6 G3 P9 |" {" ]6 G - //printk(KERN_ALERT"read ping\n");
5 {1 ~" Q7 I8 S# Q" g - }
$ m, M. l8 M* p% x% D" ?$ { - else
5 W& p- x& e0 }3 O( E S8 q - {0 x; } n7 Z# H8 l. K) h
- next_read = &res_buff.ping_buffer;//下一次中断读ping buffer# [3 L2 ?! v/ U, @
- //printk(KERN_ALERT"read pong\n");& N: _7 E1 j6 g
- }
; m; |3 L; S' A8 V! G# e - *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer, {+ }. s1 s/ i- p( p# W
- //将数据插入链队列) A4 j: k3 C( g# W
- k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);+ i, Z U' Q; i( a1 O! _
- //标识位都重置( S X; H4 \- B+ P7 j5 s0 D5 c; G
- *(res_buff.cur_buffer->data_ready) = 0;
3 G" Q, r1 [) R- w& r - *(res_buff.cur_buffer->data_size) = 0;
1 D# g7 ^' X* j8 G6 Z - res_buff.cur_buffer = next_read;) r) ^( n. `' H# G$ f* [
- }
# Y ?6 G5 H5 ?! c6 i6 g - //清楚中断标识2 P$ R6 h; ]6 O) f4 w
- *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status& V" r5 _, a- J9 j
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部 8 E+ _: e. Q8 P( i- Y/ `2 ^1 d
- 4 A7 `( a" b, y
- ! }4 d8 F( {1 U8 S8 J- k$ T
- return IRQ_HANDLED;
4 I& Y5 U. d b
; l! n6 R, o' m% E7 N- }# U# v: h8 A. i+ M. o3 x: K4 q
% `6 |0 J% U" J8 y- //文件打开函数
0 G. y1 ?% l3 C1 Z/ R9 R0 J; o7 t - static int protocol_open(struct inode *inode, struct file *file)
, J& H$ M* |- T+ N: U6 |& C+ z - {
* l3 m5 q3 L) h0 e - int result = 0;7 _2 a0 R4 d* f4 N! y
- if(!atomic_dec_and_test(&dev_available))
( O7 M) @/ s* b - {
7 K* i7 v$ T* k$ a3 U - atomic_inc(&dev_available);
* L3 W7 M: [/ s% a - return -EBUSY;//设备已经被打开" ]' T0 n; k2 s# Q% e, W9 c
- }% V- `$ Z' `+ D7 g) j3 r9 v
- printk (KERN_ALERT "\nprotrol driver open\n");
( V7 R7 h6 x8 O# ]; e! [# `) g/ w. j8 H - return 0;1 u4 y0 d: ^4 b6 ]2 | q
- }
# [7 m h( J3 B! K1 R6 _8 w3 x - ) i5 E+ _" V o2 @! |
- //文件释放函数% z' C6 r7 V* H8 l
- static int protocol_release(struct inode *inode, struct file *filp)
! }. ?. m- t5 F: e' j: i( X+ N - {
4 Q) A6 k5 `1 w$ V; y6 i+ _& ]4 \ - atomic_inc(&dev_available);//释放设备,原子变量加17 \5 i% c$ A) i. P% K, P& T% R/ Q
- printk (KERN_ALERT "device released\n");/ H! L, x) W' p
- return 0;# M: H4 c7 `0 g0 A
- }. M; a& K4 \7 B9 k, ~ X
- z! w9 `5 I: a T/ B q' {- //文件读函数/ q/ y/ y+ l6 A( ^' H( O
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)% G8 I0 n2 T$ K$ Q5 Z0 o
- {6 U& w1 x6 z0 i4 Q' Z! R
- int ret = 0;9 }8 I* q) G+ q" I: t" N
- //定义等待队列- P. C7 [; [% W' d3 H6 v
- DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列' W. k l+ L5 E9 W9 ~$ P
- add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
* _# c) m. @9 F' F - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
# @% Z) E0 i, h' Z* X - {
9 @! w$ {* b+ z5 h# t6 L - //printk(KERN_ALERT"\nbuffer no data\n");+ L8 b" {4 ~. U* j5 |
- //如果是非阻塞方式读取,则直接跳出6 W% c; U& [( ^* ?, E/ ^
- if(filp->f_flags & O_NONBLOCK)" J- {# D+ T4 T
- { J% i0 I$ A" J# A; b4 k- f
- ret = -EAGAIN;5 W+ C7 Y5 |5 c1 |( i2 X$ z
- goto out;
+ d: _# J; a! k: ]* i - }& {( J* w4 b! [+ j. ?
- //阻塞当前进程,放弃cpu资源 r6 ]/ o" g) J3 P& J% u8 x8 ]$ E
- read_quest = 1;
& G0 Z3 U0 ]3 y0 h( c+ x+ M0 G2 J5 p - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠
7 N1 X: H) i1 J6 {. G% R6 s - schedule();//调度其他进程运行1 j8 Q. m7 w' ~. j
- if(signal_pending(current))0 e( y! R3 W* ]$ @. `3 j
- {
2 y/ P) K$ o! Q+ t% f- V - //如果是因为信号被唤醒,则返回到系统调用之前的地方$ a" v v' q" F5 ]: p* E5 d
- ret = -ERESTARTSYS;5 u$ {/ S ^3 p3 b
- goto out;; K, r& c/ _5 v4 z" ?. m; Z" A- W
- }
# _% g+ I( A+ v - }
0 t$ W$ H+ J4 {& p% E" i - //将数据拷贝到用户空间
0 C% K( W4 s9 \9 V" E) n2 q( J- C, b - ret = k_linkQueue_getData(&queue, dst);, u$ B+ K' c" Y; P& P; H9 i
- if(ret == 0)
2 u# p t# O2 }3 T; w3 I - {
3 `2 U4 X9 `6 o( I' Q - //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
4 B! {& b4 `6 f( f - }
: X# e+ V/ Z. |' m0 q0 `6 n. f* h - out:. p9 a) w4 _; y+ v; l( v$ R
- remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列
6 f* |( G0 k5 r - set_current_state(TASK_RUNNING);//设置当前进程为运行状态. V- s& A9 M1 L" t- S b
- return ret;4 D$ o; H7 k, B r
- }' Z# i! B& X [. N6 [; q; ~1 I
) z) R. M! W: z" j# N e3 j
# Z8 }( B3 a+ ?5 y; O! i- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)
9 u" ^# y7 h6 ?4 N - {
t/ ]) d! a' n& B- u1 }. p - return 0;
8 \1 N) Z+ n; S/ W L1 C - }
3 D, S; e: R0 t4 U3 E - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行
4 m7 _! F# s4 e+ {# Z- l - open()、release()、ioctl()协同调用时被调用*/
7 R6 x [! `/ ]/ b/ y0 E - static const struct file_operations protocol_fops =/ k% E9 _3 A ?- C
- {. K+ m( a" i: ^
- .owner = THIS_MODULE,
5 q. s( ]1 j+ c* t- l2 W$ | - .open = protocol_open,
, u# O7 f4 E/ E5 v2 A - .release = protocol_release,5 ~% `$ l) s- x* m
- .read = protocol_read,
0 _; Q2 L( U8 V; L2 p" A - // .write = protocol_write,, @" V& o( a P9 ^2 R& p( t/ f. O$ h
- .unlocked_ioctl=protocol_ioctl,
- w- r, U3 }( `. j" T9 p - };) f. M$ f) T; a2 E O" F' m; p
- 3 [" w. l+ o: ~0 u5 G, h7 k0 v" P
- /*设备驱动模块加载函数*/
" w6 F9 a1 `, m1 \0 R - int __init protocol_init(void)& U* T4 O$ V' w' j" U+ i' H2 j" l
- {
4 ^; C- Y1 b1 s3 y% T1 H/ h: X3 l - int ret = 0;. E* Z0 e6 v) M7 e7 g
- int result = 0; { ]7 j( {( p% d' Z: p7 A% X
- //申请注册设备号(动态)# V1 v4 R' O! r/ H4 p, j8 c
- ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME);
* x, M$ A5 i8 M - if(ret < 0)
" ~: j1 b2 O- { E. N5 \% h4 s1 v: v - {, |6 t& `% v0 Y: u
- printk(KERN_EMERG "alloc_chrdev_region failed\n");* F( j9 D& X) L7 p W0 h
- return 0;0 r8 c& J: y: f U0 E
- }% x/ O+ T, j$ ]
- //分配cdev! g* w U7 `3 K$ ^/ c
- protocol_cdev = cdev_alloc();0 r' d6 M' Q+ q1 t
- if(protocol_cdev == NULL)' z+ j0 |8 U* r: |
- {( q9 X+ S; U6 N0 f& M
- printk(KERN_EMERG "Cannot alloc cdev\n");
& |' Q' N/ Q& G, H; E2 G - return 0;! r: e+ I2 Z, a: r% P! O" U
- }
4 k$ r# r! h" L* C; U7 Q - //初始化cdev O0 Q; T: v( c8 T# S( E" A4 u
- cdev_init(protocol_cdev,&protocol_fops);
9 J. k) A9 O8 K5 ^ - protocol_cdev->owner=THIS_MODULE;
; P8 [+ o/ k; [ - //注册cdev
E" Y" Q- `3 Y* [" c - cdev_add(protocol_cdev, protocol_dev_no, 1);
9 `1 k9 C5 Q5 j2 j" G: }2 P - //创建一个类
: G$ W$ _2 ?. I1 ]! p - protocol_class = class_create(THIS_MODULE, DEVICE_NAME);% K. x6 y$ {& V
- //创建设备节点
0 P% X3 a8 d5 T* E - device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);
5 X R! u6 ?' w1 _. b; n$ Y" ] - # ?, v- P& T6 F
-
2 \$ i! E+ v+ r% b - //申请链式循环队列作为缓冲区DSP数据帧的缓冲区. T3 `; D5 o6 }0 w
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区, f5 m6 {( `) C3 j6 o
- 0 r* h2 Y4 Z) B
- //映射ARM的核间通讯寄存器
; I' E$ I2 s0 X* g7 }1 h6 x - R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4); d- Q0 U, i5 I2 Q# p: ] g
- R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);
; ?* V. n3 v+ k S7 o - //将物理地址映射到内核空间/ y* H0 x0 [/ [; ]6 t
- mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);! s9 n* C" ~! U) Z" X
- //共享内存初始化0 {; A' U/ [ j! h
- SHM_ARM_Init((unsigned char *)mem_base);
+ \/ o3 f) @: l8 z6 S, b- Q6 v - /*申请中断*/
9 b$ r& J) [; ]! U! V, B - 6 p; u) A0 Z) S3 _& q9 ~' \; T& L" N3 Y
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);7 U) k- C4 `3 U c2 ]# q
- if(result != 0)
" _% x9 q4 O- v, a - {
& ^- z# D, L v! g3 t, b* V5 E - if(result == -EINVAL)
. S$ h2 q0 z7 a8 _+ W5 b& z: x/ ? - {
a1 ^2 W) Z X# c6 P$ `; t - printk(KERN_ALERT "irq request err:-EINVAL\n");
: t5 f$ V T1 K0 S. r5 x - }' n* L6 w8 \% x9 G* p/ e& H5 \
- else if(result == -EBUSY)% h. C3 q5 u, D1 [" i) g
- {% p1 ]. F+ m0 v1 i4 a
- printk(KERN_ALERT "irq request err:--EBUSY\n");
# \. V$ n5 i5 U! ~3 v0 p - }
R9 \# n- K9 @) E; O7 h - else
/ l# O% O+ m9 B. {4 U - {2 g1 ^/ a: E. P: L o# X# B
- printk(KERN_ALERT "irq request err: unknown\n");
3 a/ ~: ]* D6 B; u1 M* Q - }
, f" [% M$ C+ Y9 y - return result;$ Q6 e i3 E1 u+ c0 A
- }
O# U. i2 r4 J - return 0;( h0 d4 v. w' R# x: K
- }
: s2 p# }2 \! t) h1 C - . G( P: z' D6 ^) _" k( k2 \8 h
- /*设备驱动模块卸载函数*/
* S! ?# s5 d' h8 B: g - void __exit protocol_exit(void)
$ D6 ^2 G2 u8 b' ?+ _( w - {# z# Q+ m4 r' J, b% t! A# @
- /*释放中断*/$ O9 }, x# J l: F" ~9 G! S9 `
- free_irq(IRQ_DA8XX_CHIPINT0, NULL);& q0 c0 ^6 s$ n+ O
- //释放帧缓冲的内存
& {7 K; S% G5 a* D' E* K6 H' B - k_linkQueue_release(&queue);
- [$ V9 v2 c. w+ x# R1 [- [; j - //释放寄存器映射
$ Z( S, e- k: k% u; P- L - iounmap(R_CHIPSIG);! ~0 q K9 j9 A
- iounmap(R_CHIPSIG_CLR);
: C6 b' j# K9 |) q" X- S - cdev_del(protocol_cdev); //删除cdev( _( T# P- L, J& f
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号
7 [- O: a3 S! {- k - device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
9 r1 g8 q( Q+ ?# y% W- U- i - class_destroy(protocol_class); //销毁设备类# U8 X& j4 P5 v( ?' i9 d
- printk(KERN_ALERT "exit success\n");
- }3 ?" j, E. F. N- Q2 x - ; U. b' f" o% r; [/ z6 L
- }
9 @/ v* J3 u' f$ L5 C - //驱动其他部分省略
复制代码 6 e1 Q' Y0 @3 O+ l! U
6 K' A2 B& \8 d% R
|