本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑 6 }" k' x3 ]8 c" f. c
1 [( ~* |5 M8 G& @5 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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略
, Q, U' N9 d1 g" e4 i1 D3 Y
8 g; v# u) S# J2 t S# Y3 ^" V; y- //引入其他模块函数和变量/ x# |) N# u) l% L: T9 h
- extern Ping_Pong_Buffer res_buff;# @; D+ y0 h# d# P- q6 i( ^4 m
5 C+ d0 n, |: K( M. e, Y- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列7 d' O: j( P' o) S& ~8 }6 e
- extern void k_linkQueue_release(linkQueue *queue);//释放链队列
' S$ }' k" g6 V3 ~ - extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据/ p+ ?1 ]( O/ B" B1 v/ o
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据$ n& u% O4 E3 Z2 a- q' n
4 p2 h2 F$ t6 _# o/ z( Y6 ~- Q- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化9 N9 D8 w9 o0 K1 y" N
) q/ @/ e6 r( L5 j- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1 M8 g% F- p% h9 ~" T4 }* @
- //设置主从设备号 q* O& T- w! M0 k5 f' J; k
- #define PROTOCOL_MAJOR 1
( Q0 [9 }4 O' I0 \: C - #define PROTOCOL_MINOR 0# l+ X' j7 Q0 G8 G& a7 r
' R3 |) R) v2 n, Z- - v7 L% h% Q+ F
- 0 m- D4 e6 c9 K/ X- I# V4 r
- //定义设备驱动的名字或设备节点的名字
* w: E; K( \- H - #define DEVICE_NAME "protocol_driver", l: F% y! G4 O* d; O N
9 V5 S& a; R6 v* M- 7 C M4 C1 R) L0 l2 u- U
- //定义全局的循环队列作为数据缓冲区: A1 d$ t# O# o5 M: |0 Y" U
- k_linkQueue queue; Q" A' L/ v& G% @7 F! R
- 1 m8 Y1 g% r# a' T0 Z$ x
- //寄存器地址映射全局变量
' M- e* ^ S% O4 p# V! Z/ G( F! B - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器1 `0 b& }; M# w6 q, W6 k1 k5 j$ j
- unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器; `$ d. V$ b6 y+ W! r- \
4 p. ^5 C# b0 r9 J! g) \- a- //物理内存映射全局变量
; V0 ~1 h( O$ f& c - volatile void *mem_base = NULL;
; K% x- J$ O, Q$ G! A* _4 p - volatile unsigned char *cur_buf_ptr = NULL;3 P" q3 h9 w" I/ M
- volatile unsigned char *data_ready_ptr = NULL;
6 f1 x' X% u: U4 G& s2 l4 q
& ~4 }0 y0 J6 N7 G- ( V- K7 _3 O, x" R, _7 `8 x: K
) F& o; d! N+ G% f& n: v% V5 _1 t- //定义读数据等待队列头,IO阻塞$ f% Y) M+ g9 h7 E$ C
- DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);: p! d2 }) x0 x0 g! q6 n1 @- ]0 M
) a) x+ L) [' L/ Z8 R- //定义原子变量
+ B. d2 r& T+ c) P& |0 B - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备
8 }9 B2 q: F3 G0 y1 U" j* R+ f - 5 h) T- d. Z j) y" }
: F' _5 k3 l5 {8 y$ o, W9 s- //定义设备类. @. V& C9 z7 h
- static struct class *protocol_class;
8 Z# S; }0 e, b; m s$ i - struct cdev *protocol_cdev;
2 \& r. A* j4 ]% L! Z- w1 E - dev_t protocol_dev_no;
: k `; U' m6 k( m+ @+ z
& h) ~5 k% s- E, T9 w1 d- /*定义tasklet和声明底半部函数并关联*/+ V9 j1 f- ^6 r& \; V
- void read_data_tasklet(unsigned long);
\5 Z+ n/ h3 k+ N& x
, ?5 I# |$ ^" S- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
3 i, U0 J' ?9 n - //将CHIPINT0_tasklet与read_data绑定,传入参数0
8 t" k, j7 ], U5 N4 z9 h - % ~* |" M5 \5 J
- /*中断处理底半部, 拷贝内存*/! m8 e0 O; {3 O* F9 a
- void read_data(unsigned long a)9 c- X( G" i0 S( S
- {) n. s% b! }, T, H; X
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1) _% ^% Q5 H6 ?8 N
- {
% J+ |1 ~+ Q5 G1 ? - read_quest = 0;
2 p' N" `0 {+ O4 Y+ I, B! a# J+ h - wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
. C" F% w7 E) Q0 E. C# h0 A - }
8 J5 C) z' d8 d- t
- o& t+ j7 {+ o) H: X) L- }
% \$ `7 L0 R2 z- ] - , A1 |3 a, h7 b. Y
- /*中断处理顶半部*/0 a6 f4 N0 D! y; {1 A
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)
7 Y/ j4 c' b) W - {, M: _/ F* Q6 Y2 V3 u
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
3 X# k) Y j1 B2 P - volatile Buffer_Type *next_read;& ~- ]- t* |6 u( |
- //如果DSP数据已经ready
; s2 q* }- ~' K& v1 h7 ` - if(*(res_buff.cur_buffer->data_ready) == 1): x# L) s% t$ C9 t, C
- {- U5 @2 {& J; P$ K; O, `$ y% k+ D
- if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer
2 q' h L5 s3 n* I/ r - {
. k# q4 W/ P, F - next_read = &res_buff.pong_buffer;//下一次中断读pong buffer
8 X( l, Y2 l. E8 H - //printk(KERN_ALERT"read ping\n");; m; a6 T9 R$ E; m* J
- }
" r! K$ o6 R# l0 q1 ` - else
8 F) I6 O& w( D7 c* _8 ] - {- s C# u- j7 ^' F
- next_read = &res_buff.ping_buffer;//下一次中断读ping buffer3 C# `) F7 ?/ V: ~# M2 z
- //printk(KERN_ALERT"read pong\n");' K3 ~7 \# w% y5 |
- }
- @. }& B4 A; X! J - *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer) m2 r# J! h7 D3 L) f5 s$ l6 _+ i
- //将数据插入链队列
0 w( m5 \* x- ^' T6 M6 [ - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);) R- x) N5 k; ^- A4 W* V
- //标识位都重置
) ?0 T4 F( A5 O1 J7 X. ~; E* g- R - *(res_buff.cur_buffer->data_ready) = 0;6 \5 i% O( O! e7 N9 D) M
- *(res_buff.cur_buffer->data_size) = 0;
/ I9 o1 v& \ O - res_buff.cur_buffer = next_read;2 V8 f# n3 d% ]( o$ y
- }
3 t( |& `& X" l - //清楚中断标识
8 a) f" R7 j! t) Q: C. ] - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status
7 ^' X/ I* w6 g6 R0 X( n - tasklet_schedule(&CHIPINT0_tasklet);//调度底半部 $ F4 V! Q. D( z3 k' e$ m0 e/ @8 N
- % | O. g9 B3 ~. h$ ~$ A( ^- c
6 |0 U9 u) p/ r1 c8 a7 b a- return IRQ_HANDLED;
$ m: ~- i1 i8 M c& `0 [6 L! O6 v
& c% K+ H' Q( l$ ]- }8 w- P* Z3 n4 o3 v0 E. W
5 v( V6 }' L7 V4 q- //文件打开函数0 ~' I* n2 U5 k2 z1 i2 y* t' O
- static int protocol_open(struct inode *inode, struct file *file)
" s2 K, [/ R' W( E. ?$ {2 q3 h - {. w1 Y! D$ j9 i' k$ ]9 v8 ^
- int result = 0;
, W6 f, Z9 U9 Q% C - if(!atomic_dec_and_test(&dev_available))
* x. P0 c- ]' _ F8 [' C; M: l - {
& V, r8 e9 p: e - atomic_inc(&dev_available);! P% c; ?& B5 K: i
- return -EBUSY;//设备已经被打开& z1 [; Q" L& H S; W* a c& `% w
- }
* ^2 v% N; H' M* ?1 A( @( j - printk (KERN_ALERT "\nprotrol driver open\n");
/ T+ z. y. W7 X4 h - return 0;: R5 Z z: M" n5 O
- }
$ X1 A) d5 N( y9 Y4 G; e$ g
8 R; N7 l4 Y; c; i I- //文件释放函数( o) {$ h: \* [* a3 T: d3 ^
- static int protocol_release(struct inode *inode, struct file *filp)( q% _3 }( W. H
- {1 G( ^* N% q( n+ C7 c# y A4 t
- atomic_inc(&dev_available);//释放设备,原子变量加1$ w4 g' |) O; O8 ?
- printk (KERN_ALERT "device released\n");, x4 S4 [2 K0 q: \- n& |" L G+ s
- return 0;, A- ~) [2 u# b4 I
- }0 k# R+ v0 {) y* c5 ^
9 C6 ?1 a. P& R8 Z/ w- //文件读函数5 l% |( U* C3 V7 k$ n
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)5 @; W: Y h/ e! ]
- {
- \! p1 u1 r6 m5 }8 N$ n - int ret = 0;
0 }) _5 r5 K; L _0 Q3 |$ @ - //定义等待队列, g1 g/ C8 e1 D. S
- DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列
6 o$ @( P+ k( F! T1 E - add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列% N+ U. w) K" D) B* w. J% H. d/ \, m
- if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
' o+ ]3 y! w$ D0 ~, }& d8 W - {
& D2 Z; W W, ]6 v( f& T) f - //printk(KERN_ALERT"\nbuffer no data\n");
5 V7 \6 d. V4 r' b! I - //如果是非阻塞方式读取,则直接跳出
5 e0 S5 U4 `4 n. Z( m k, z - if(filp->f_flags & O_NONBLOCK)
4 y( I4 D/ b( ?7 ^ ^2 K) Q, p - {
' n; h x) D9 H" h% ~- z! L" A - ret = -EAGAIN;
& d1 Q) U$ X7 _; h0 C; r: m" ~3 L0 \ - goto out;+ V* g+ X# P0 g
- }. W2 C$ [0 p3 n/ ~
- //阻塞当前进程,放弃cpu资源9 o3 l; D% n8 J0 U
- read_quest = 1;
4 w# B+ ]2 W' K. Q4 ]3 d g - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠
& Q0 q. j) ]* a9 v: f+ l - schedule();//调度其他进程运行
& q' L4 M) u, _* Y' s: L - if(signal_pending(current))
, z' H; e" r8 b( `+ M7 B ^ - {
/ {0 B7 B6 R1 ]. E - //如果是因为信号被唤醒,则返回到系统调用之前的地方
0 p7 T t6 e6 k: Z( z' A+ I! T - ret = -ERESTARTSYS;1 U, G9 D8 B+ }- w
- goto out;4 ~: h0 m6 T( k) ]4 o( \
- }# G. q$ W, f" Y
- }* A# R# c5 i4 }
- //将数据拷贝到用户空间& r7 \7 b8 I& z" f3 h- p
- ret = k_linkQueue_getData(&queue, dst);
" p# z3 \4 L8 x' ^+ n8 k6 S) B - if(ret == 0)( m. O- g5 g: t j
- {2 v; S) T! w% p4 j3 k8 P9 F4 }
- //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret); }! H, ~: Y# Z0 F' e& D1 G: K
- }
& U, a9 t. X9 v# V+ }) x - out:7 Q5 ~& j+ Q: p% e8 T: p
- remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列
% F, h/ m6 Y! S5 |: j0 g! F3 M - set_current_state(TASK_RUNNING);//设置当前进程为运行状态8 v" ]# `* A5 e3 D
- return ret; ~2 {; q- U0 ]+ u
- }. \% s4 Z1 Q; Y$ Q$ P
- 7 e3 m/ M$ g- o: ]) @
8 r% M" T; w! ~8 _- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)
/ g7 D7 p% k& ]' O - {
" Y: O/ t& n7 ^1 i; t) \( e - return 0;
3 E, y( X2 I8 K9 q7 O7 ^ - }$ {% \. ]# [, x
- /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行
3 u# ~1 b* {+ J7 ]% i. N9 d2 ? - open()、release()、ioctl()协同调用时被调用*// L7 S/ W7 l2 X, c4 y3 B& ^ m
- static const struct file_operations protocol_fops =: g. r0 c7 T7 m0 X" H! [
- {: V0 w1 d& D5 ~3 [/ s ]5 K; x
- .owner = THIS_MODULE,
( K% N; n$ s9 r8 f! N - .open = protocol_open,
( t5 L+ P8 G2 k. j6 y - .release = protocol_release,8 d: ~- T' S2 I0 q, t
- .read = protocol_read,: P9 b5 C3 E) C9 q T
- // .write = protocol_write,
: t4 x# s* N3 C' j7 b$ U - .unlocked_ioctl=protocol_ioctl,
6 y6 @6 R* N$ V N+ X+ }( t - };' a# r' H, S7 V% X! B8 i
l( ?4 X* m3 T' \* z- /*设备驱动模块加载函数*/
8 ?; k' R0 {6 ?' ^ - int __init protocol_init(void)& k; _( R+ k/ m: R$ I- q/ G( U2 H
- {9 A& G) j* N1 n& |$ x; {8 ]
- int ret = 0;5 q' j3 w3 @, ?9 E4 X' t1 o4 G. b% T
- int result = 0;
5 j. g `9 u! a( d - //申请注册设备号(动态)5 K& N4 J6 Z" x+ Y9 X* B
- ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); % Q. P7 r4 g' O9 V! [
- if(ret < 0)& a: z5 B5 s3 O' n# I
- {
. p2 M: \! G* }! k; U* b( s - printk(KERN_EMERG "alloc_chrdev_region failed\n");! c- w, B [: U! r
- return 0;
& X1 J: E# B: p4 M* v - }
: `2 _" y9 J6 V# U5 O - //分配cdev
O. R4 y, q" [+ p" q - protocol_cdev = cdev_alloc();* \7 Y7 w: p2 M6 W& [
- if(protocol_cdev == NULL)
* p m" H/ e' Y5 E1 Q - {
8 p4 `7 r$ l7 d: I' {( k - printk(KERN_EMERG "Cannot alloc cdev\n");
6 U/ _: h5 K! v" o% x! O. H - return 0;
9 ~ N9 U- x) b1 Y( s - }
3 F7 P! Z. k6 B' e7 r - //初始化cdev: i- P4 C2 B2 ?9 Q
- cdev_init(protocol_cdev,&protocol_fops);
6 l8 A5 l, T5 @! N9 \ - protocol_cdev->owner=THIS_MODULE;0 b/ ~9 k e0 r; ~
- //注册cdev
: [8 s2 N: I, j8 Y - cdev_add(protocol_cdev, protocol_dev_no, 1); : J6 s- G: A, _
- //创建一个类/ Q# G6 q5 |0 T4 t- z3 U
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);
& R! ?4 z* a! f1 n) g - //创建设备节点
3 [. T4 ` M7 s7 v# v- n - device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);
$ T1 A- H/ S% m* f -
& ^6 N. ]8 x0 v$ s- _ -
$ z3 [# y* q! n' t7 K- {2 ^ - //申请链式循环队列作为缓冲区DSP数据帧的缓冲区# N- Q% U) `1 x
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区/ K, y8 z) g; x) x3 q. N* X# r' j. G
2 w0 f1 o) }% V; P. m5 {) p- //映射ARM的核间通讯寄存器+ Z7 R' \+ Z* w# x$ g, |" Y& S& h! p$ i; h
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
- r- A' d& F( _% u - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);* E+ M* c- z. K; C% l! }
- //将物理地址映射到内核空间; z4 i6 F6 D) Q( j7 e9 }7 p: v
- mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);
4 x! Z! ?' {$ ^7 n - //共享内存初始化/ ?4 M! |1 I2 w, }; n
- SHM_ARM_Init((unsigned char *)mem_base);
) g: Q9 N% f6 I" @( o: ~5 h - /*申请中断*/
$ B5 u6 L0 ?; b) s2 x& Z- E - 7 R, L$ W E8 B- _
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);
" M: }% A! ^' G, v3 I" q9 m5 C - if(result != 0)7 O' b8 t& r' H8 }
- {# g* K2 R7 s# r# J
- if(result == -EINVAL)& y0 E- w4 m) H8 M
- {* D8 F$ z# \" M0 w ~
- printk(KERN_ALERT "irq request err:-EINVAL\n");9 g+ u7 K" q& |/ i
- }2 c( M- E0 A6 G9 ]& @5 j2 n
- else if(result == -EBUSY)& N3 y. o, U8 B: n, |
- {
, ?8 V" ], x8 P - printk(KERN_ALERT "irq request err:--EBUSY\n");9 w! \5 A. r% U0 y8 k) c
- }
% b! y' Q$ }' Q0 A# u7 e - else
! t+ d( M: g1 o4 ]! y; z, q - {: F2 T8 Q( P% E: a$ q- b" K4 W
- printk(KERN_ALERT "irq request err: unknown\n");# L5 I( r/ P: T' N
- }5 S5 [& d3 g( g$ Y1 ?' T
- return result;6 H7 u3 Q- M* r+ s
- }( l4 d) I M; v" S8 ]! `, o
- return 0;
% t8 `) e7 D. J) ^' ^" F) N - }
; J/ e2 d0 U6 \# H5 u4 E - ! c4 Z$ E- S; u4 D: N- f
- /*设备驱动模块卸载函数*/( Q0 |( _1 ~+ O4 d! n" c
- void __exit protocol_exit(void)( X7 ^( z& E' a+ A' k
- {
& C$ V2 h( ? b8 V+ r3 b - /*释放中断*/$ v) D& ?( ~, A, g* K
- free_irq(IRQ_DA8XX_CHIPINT0, NULL);3 o- e" R- l6 N% _
- //释放帧缓冲的内存
- L/ R5 X1 u! m( ^/ Y( E - k_linkQueue_release(&queue);9 g' W4 b9 U% ^) _0 S0 `
- //释放寄存器映射3 V9 w/ D/ D1 `; J: y8 V
- iounmap(R_CHIPSIG);+ d& _: f- J/ |
- iounmap(R_CHIPSIG_CLR);
7 S8 I1 _8 s! X* v/ n - cdev_del(protocol_cdev); //删除cdev& K9 C, r: q, e( A
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号
5 E( o' D2 `* @" s: Q# v+ O - device_destroy(protocol_class, protocol_dev_no); //销毁设备节点% f% O, L3 i" n# \
- class_destroy(protocol_class); //销毁设备类
- V" V' K$ V& F, d - printk(KERN_ALERT "exit success\n");
* H b3 }* z& _# Z. m" K
% o% _, J( v o, j- }# D. R+ I1 Z7 X" U9 D8 K+ Y) K
- //驱动其他部分省略
复制代码
, _/ c, @$ R2 @. r1 P* ?2 w: v* ?- E/ H) n3 G% e7 I$ X
|