本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑
9 N, r3 }) P6 F. Z9 @1 E% l8 P. f; H- u) }: [# {
项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略% Q1 y$ s, Y7 g& d7 [( C# ^* M' ?6 P
; \8 L. V! c! D- //引入其他模块函数和变量6 p& I; r! |9 Q1 K* u% b% z
- extern Ping_Pong_Buffer res_buff;" q- S& O6 S/ |1 ^( K) U* _! w- H( t
/ I; h+ P7 W Y- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列
5 ^" V0 Y4 Y: M+ o z - extern void k_linkQueue_release(linkQueue *queue);//释放链队列
# F' N& b) Y5 n5 y, D: U - extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据
& T9 m7 f ~' q$ q4 J6 Q - extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据
6 v) u- |7 |) [: Z - x5 R# c7 {% v7 d, ], Y* A
- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化
" y' k( M6 c7 v* i) n3 L& X9 y, A# d - / u7 S$ w i1 ]; i8 U
- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1
1 a' D6 M; q! c: Z - //设置主从设备号
Q( l5 I1 z5 y }3 k% s( j - #define PROTOCOL_MAJOR 1% \6 \' c% l. S5 U+ \1 T% M
- #define PROTOCOL_MINOR 0- W3 {9 {& B6 W3 J y9 n
- {) ?7 T0 o! K
- & F2 z8 f/ C3 z' {' J# j6 G
- , Q4 Y$ o- P$ a+ S( f) K
- //定义设备驱动的名字或设备节点的名字
# ]. S: R. |1 v: m" W/ F6 R - #define DEVICE_NAME "protocol_driver"& D$ C, ?. J! [: G% h6 |; f
- 9 w/ i7 [* d! W7 y: O! E) f
- 5 x |/ M5 N" B( W: P
- //定义全局的循环队列作为数据缓冲区8 }% x& W6 ?' h2 Z/ W, K% K
- k_linkQueue queue;7 k; ~$ G: O! L% I
- , g$ l( ~$ Q7 M' E- r0 T5 h
- //寄存器地址映射全局变量
1 b; Z% H* T$ Q1 ^9 z - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器
: j. L1 A7 p8 n! n - unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器. |. o3 Y, w% k) B- v
- 7 X# ~) n7 V5 t. ~' L. M" f Y
- //物理内存映射全局变量' I7 I$ j, @" A3 r) p
- volatile void *mem_base = NULL;$ I* d/ D4 ^" l- i+ h3 ^
- volatile unsigned char *cur_buf_ptr = NULL;: Z1 W( I' V3 l. R, x, D* G
- volatile unsigned char *data_ready_ptr = NULL;1 G/ n6 t2 w2 |
- " p. l9 W0 f6 ?# s; o% n( `6 |
6 T9 _; h& o2 N* l
8 ?' R9 k( k3 f$ }3 f6 {1 M- //定义读数据等待队列头,IO阻塞3 N! H; C. t. M
- DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);
5 D p8 P& _7 i/ P1 ]. V% c
6 U2 B2 A v- [" V2 g- //定义原子变量
8 t3 v& u4 S& s* E$ ~ - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备
. E! p9 I- Q* s$ u5 N; E
$ e+ H. T9 q4 Z9 @* m- @. f
9 ~8 w a, D7 R d, z, z/ D- //定义设备类5 B+ @8 ~. y9 W: }" [
- static struct class *protocol_class;) W5 R! a9 t3 `5 r
- struct cdev *protocol_cdev;
& ~" i5 U h$ |; Y$ G6 y - dev_t protocol_dev_no;
3 \9 x1 G4 t/ c( U) [4 k) B+ G: L - 7 ~' X3 ~4 t3 @) L
- /*定义tasklet和声明底半部函数并关联*/3 S' Z3 N9 y* L: [% K5 m5 s- h
- void read_data_tasklet(unsigned long);# u0 W: z @) c* w: w: S" G* p, {8 f, B
- P; o, l# \, G
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
- e% ^6 @" f6 a - //将CHIPINT0_tasklet与read_data绑定,传入参数0% t1 i4 a6 v" M1 b
- : R' F/ J0 c8 t2 d$ K q
- /*中断处理底半部, 拷贝内存*/
X5 J* N8 U8 j0 V+ } - void read_data(unsigned long a). d4 a+ ~% \, ~' k
- {
3 n. T- y& O6 A1 v! { - if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1
& E8 V! d2 H2 s - {: i0 ?; E8 u0 z: ~: x9 H2 l8 P
- read_quest = 0;1 g, L! [: h- O) v2 H; g# B
- wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
$ T) `) Z. G. I/ P - }
8 c5 i, G+ O( o7 o, p
7 l6 b4 m$ Q% y- }1 e3 N G$ m& R3 Q% U/ F+ L8 X- z H
9 ~0 L, Z2 q( ?- /*中断处理顶半部*/
/ W0 q, X0 Z4 V1 b! r% B1 A% V - irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)+ o. t7 k- L( y, K. Z' C
- {! s6 ]' m% J" @8 z
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样8 V, e; ?# e% h2 ?( _ i3 J
- volatile Buffer_Type *next_read;6 E) i5 v4 i) r" M# A D
- //如果DSP数据已经ready( F% I) T* u- O: L2 t% l }1 _" B( B3 U
- if(*(res_buff.cur_buffer->data_ready) == 1)) b O0 o( K7 C7 M
- {
* n6 v v& j$ T4 s - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer
+ M9 R( v' N1 \5 V' @ - {+ h$ K6 a. ?9 w9 K
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer+ g2 Z. Q9 V& X% d1 c% ~
- //printk(KERN_ALERT"read ping\n");
1 m; [) r' u, T' ?2 t9 s - }
F1 I; |1 r9 w; Q% y - else2 M* i/ ~4 h) T. l/ e
- {# o2 U! N+ A. {) [
- next_read = &res_buff.ping_buffer;//下一次中断读ping buffer
0 p! B7 e: c) L2 N5 B* Q8 Q# [ - //printk(KERN_ALERT"read pong\n");
6 _- z; K4 a6 l4 K - }% C- c; W0 z. h! V# ^( {# l
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer
! i* _4 J* D7 C/ z6 E - //将数据插入链队列
9 ?. u: ?5 ~3 L8 z - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);
- q6 N; N( O. g, A X - //标识位都重置
, T" @; ]6 k4 c& p5 L3 L- { - *(res_buff.cur_buffer->data_ready) = 0;2 K5 t% E o7 `3 |6 _$ U8 {
- *(res_buff.cur_buffer->data_size) = 0;
2 E, \4 V& R2 B7 P7 k - res_buff.cur_buffer = next_read;
, S& A7 w" A8 p9 ^ - }
/ C" L+ l5 ]& b8 E+ c# {) U, x - //清楚中断标识
- b5 g& k, q7 i" _ - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status
o3 y' ]( ~# c2 w - tasklet_schedule(&CHIPINT0_tasklet);//调度底半部 9 e, D) b$ R' I: r' X! N# ]
) h- P+ o" }$ [4 z0 \1 E
4 \9 ^$ F5 t. G" F( \- return IRQ_HANDLED;# Z) W! D N0 k E- j' q
9 m3 Q$ o+ z# P' W, u9 j! c) C1 n5 I- }
8 O1 i/ x( x1 o5 N0 b. r, l* u - ! b- X- C$ c4 k% Q5 K
- //文件打开函数; z: H$ {: E' Q4 ]
- static int protocol_open(struct inode *inode, struct file *file)
1 g R6 |4 w* H- M! b - {) E9 H4 V {4 G2 s- ^; t3 V! e8 Q0 O0 h
- int result = 0;4 A! X9 K: ]6 U8 L- L4 V6 y& K5 k
- if(!atomic_dec_and_test(&dev_available))
4 @% J6 p, t- p2 A, ~* Z' D P - {
6 E# t6 q, B* F( a - atomic_inc(&dev_available);
% i# f% Y9 }. ]) |! y - return -EBUSY;//设备已经被打开, z( j0 k- L4 | g6 K
- }1 E1 p& t. R7 r3 z
- printk (KERN_ALERT "\nprotrol driver open\n");
1 w$ M9 [2 G' P) o - return 0;
/ c( ]5 j. G7 d+ h: g0 _ - }
8 O' O# m9 E: k& H- F - % e5 m8 P& u; R l
- //文件释放函数
- F4 D8 z* U2 l( d$ h6 D - static int protocol_release(struct inode *inode, struct file *filp)
% t& ` P) Q4 Z* s: \; R4 x - {
( w* \! [( @6 y2 o0 h2 g b - atomic_inc(&dev_available);//释放设备,原子变量加11 P# z( O5 \4 \
- printk (KERN_ALERT "device released\n");
/ I# e) _5 e \% s$ p. i9 F0 v - return 0;' N* \- Q4 \, p, I/ S
- }& [" B+ ?2 S5 w8 j! n% {- y+ G( I5 i
0 C1 N; ?+ L( P1 h$ a- //文件读函数! ^/ _8 A6 \) g* h3 Y& w6 L& w
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)
B5 A$ ]1 q, u f/ o - {8 P% k: u! o2 S2 \, V
- int ret = 0;
- ?, f" g, v: H7 v- l - //定义等待队列
4 m' _* ?( d( t+ W! k% n; v - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列
- s; _/ ^! ~$ b g+ A/ ~! d6 J1 ? - add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
' u$ E, i' n7 O5 g! [/ b - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
# D2 q8 G8 q6 |7 s - {" H6 Y2 i5 R; a0 _
- //printk(KERN_ALERT"\nbuffer no data\n");
, K, b" \( C! C5 D9 ~) c - //如果是非阻塞方式读取,则直接跳出: }8 u1 f; t: Q+ R# |
- if(filp->f_flags & O_NONBLOCK)
+ L+ {8 e w% |2 N - {0 t; B; @2 F1 m
- ret = -EAGAIN;" \& p2 g0 _) k( Z
- goto out;
: A' l8 E# M# f* L3 [7 e9 B - }1 Q7 }5 ]# Q/ m7 F6 E+ ]0 _- a9 g; t
- //阻塞当前进程,放弃cpu资源
( ]) l& |4 O- ~ K9 G4 v - read_quest = 1;
' _5 u( g/ A% F - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠
! l* ~8 J8 b' V& C - schedule();//调度其他进程运行
: F5 H' Y: w _5 c i4 Q - if(signal_pending(current))
2 x6 `- a! g4 ~' L+ a* g0 x! ~* y5 g' `4 U7 n - {
, }; v$ y( z; A7 E" P' q - //如果是因为信号被唤醒,则返回到系统调用之前的地方7 X& Y; h! ?3 K$ i: j6 c5 T
- ret = -ERESTARTSYS;
% m% q! S7 C- A( J - goto out;; t* N/ g8 g0 h( I$ Z
- }
: r/ }2 D% X& i! E9 q5 A! B. W - }
$ k- o) \5 L% o: W - //将数据拷贝到用户空间7 k7 d0 f, }& ]( I% N
- ret = k_linkQueue_getData(&queue, dst);
$ O" w3 ^0 x* x5 T6 s: z - if(ret == 0)
! f) x$ K6 Y7 V% j: p - {4 l9 _( G3 x% s# k/ E& E
- //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);. v" }" R- r9 W- `) ]% Y& O
- }
* F8 v) `/ z9 n6 i - out:6 B* ] y6 F! ]
- remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列
* I, A; G& y* P" k - set_current_state(TASK_RUNNING);//设置当前进程为运行状态
* {9 ? C4 p2 ~4 U - return ret;
, B9 u' ~/ r8 |3 A4 ~4 E+ a& j/ M - }) z& h$ I9 e A2 }
- ) B7 t9 O: p8 q8 J8 g/ I
- {) `% \2 U( F& V( J8 y: h$ i( v
- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)' f+ J. m2 i* @0 J( n
- {' B) |! E, q& e2 h x& @$ x
- return 0;
) H! O4 N4 F9 V: S6 B1 k - }
. n1 J# u( @7 F; ~7 g9 j. O' p7 D- G - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行
: m: U/ b! W6 X$ U6 X0 l: c7 a' l - open()、release()、ioctl()协同调用时被调用*/
; Z1 U t! j; i2 v1 v - static const struct file_operations protocol_fops =
( R* t% F3 e- k" @# m! e - {5 P+ G* w$ \3 v) r9 ]
- .owner = THIS_MODULE,
1 d; T; k8 {$ m4 D - .open = protocol_open,$ |( Q7 c0 \: f% |- l" j6 s* \# O: u
- .release = protocol_release,
0 @* c" P4 I9 A4 {; m. ^ - .read = protocol_read,
) f3 w5 k+ f3 _! p& r- J: ` - // .write = protocol_write,
4 c1 f' T$ t* C0 r: Y - .unlocked_ioctl=protocol_ioctl,
2 U( x. Z" c `" Z/ \ - };9 [4 j) Q9 ~2 H
8 C, b$ b" F; P- /*设备驱动模块加载函数*/& } O( `# s* c% p. ]
- int __init protocol_init(void): b7 H6 t, c, v# w, r- r
- {
; z( ?# S+ ]) [8 _8 x4 c* @& G - int ret = 0;+ V6 j) M. T& B9 a8 G. v
- int result = 0;2 j* T# l4 v" A3 [1 o
- //申请注册设备号(动态)
' N! F( }- F# ?' j4 X2 D, ] - ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME);
7 f! n, v& g0 }" i. y; J - if(ret < 0)
; u( B% j' s6 x7 L% i4 s% d5 V - {; V: F! g* G }# c6 @6 b% h
- printk(KERN_EMERG "alloc_chrdev_region failed\n");
& p0 V3 W1 }2 x6 y( p - return 0;
, h6 J. g& N5 z. v' W - }
5 y" `7 R1 q0 e - //分配cdev u, F; r+ f( }9 d4 p
- protocol_cdev = cdev_alloc();
+ W8 B) x* y; L p2 |1 g - if(protocol_cdev == NULL)
# R: W" L( i, {4 a: V" j3 V$ X6 B - {- u+ a# n7 g$ R8 d
- printk(KERN_EMERG "Cannot alloc cdev\n");
9 J9 n) p: K0 i7 D, V0 | - return 0;' Q) a7 x+ f! z* k
- }
/ L2 p& ]5 Q T9 O3 T0 p$ K1 O - //初始化cdev
1 V: A! [; x4 j6 o9 t" |+ H; B1 N - cdev_init(protocol_cdev,&protocol_fops);
% y- h4 a; s! q B - protocol_cdev->owner=THIS_MODULE;: P% V9 `$ J! U' a
- //注册cdev
3 K. v& h% t3 E1 c6 D y, D - cdev_add(protocol_cdev, protocol_dev_no, 1);
% f2 q1 w& L& J+ L; |: y3 B0 f2 B - //创建一个类3 v: a2 n" x' K/ o- ^, C
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);
' g( G6 k* t" y, p - //创建设备节点
; [7 p! W+ t8 T, X - device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);. @# j, j& W0 @' S
-
( B9 n' B; k0 P, b6 q7 R2 b. q2 u7 S Z' \ -
& T3 Z1 P5 l8 Y0 }7 y - //申请链式循环队列作为缓冲区DSP数据帧的缓冲区8 y* a4 E) i9 d6 z! y
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区0 `1 A4 n% O! a" f9 h6 ~. C! I
- ~+ q. ~3 Z& X1 m
- //映射ARM的核间通讯寄存器6 P- {7 B( L" D' P+ P
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
# |! _9 S3 O0 l: t - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);7 L- ]* p, j+ d9 @
- //将物理地址映射到内核空间
X W1 _ W- T7 E - mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);2 N Z4 h8 c! r3 w( d; o' ^" h" {
- //共享内存初始化
% U7 m% \% ^2 y5 p a: x9 G& x+ l - SHM_ARM_Init((unsigned char *)mem_base);2 q! U3 w; B' w/ N1 H
- /*申请中断*/
( m, }( V: ]/ _/ z d - 8 y! M% R' u0 x. R1 _5 K! c
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);2 o4 ^7 Z1 y0 L3 z( h3 B
- if(result != 0)
$ P* v4 F, u( E, S: I3 b0 p: h/ I - {8 ]3 B- L" c; b6 B7 I Y
- if(result == -EINVAL)
2 z# Y N4 c% X( F - {/ D( P" b4 t, w6 B% L; c" H8 b
- printk(KERN_ALERT "irq request err:-EINVAL\n");, a: y6 P: x9 S! ?1 j. T
- }; l0 |" P8 Z5 I
- else if(result == -EBUSY)
: U" x) @& \4 Y3 v. K, t - {
u* f }( A/ U4 t' `! X M! E! y - printk(KERN_ALERT "irq request err:--EBUSY\n");5 b% J/ F5 P* Q4 N U$ a: w
- }
/ f. |. o2 O& o" S. I2 B5 R - else
& @1 B& _$ I4 W% X. d - {1 \3 N1 C% s$ s
- printk(KERN_ALERT "irq request err: unknown\n");2 {! y/ M5 U/ \" g; }5 v/ ]3 m
- }
5 q6 c+ D' @, l- A5 R/ j! E/ R$ U- E - return result;9 W. |/ Q! b, G7 `
- }
* }4 ?& T1 v# ~$ {2 A" a. R - return 0;+ \8 E0 w# c& I3 x* f) d
- }9 [3 t' D6 _' b v% ?( L$ @
3 E. F% c! X7 k6 t6 @, v L- /*设备驱动模块卸载函数*/
/ n4 w2 B/ ?; R8 g, j - void __exit protocol_exit(void), _; l8 T4 H, p' A
- {
8 \( ]; X. e: j! U3 d - /*释放中断*/; g5 E7 P' m& ~% F
- free_irq(IRQ_DA8XX_CHIPINT0, NULL);
* W; M8 l) o. r n; h; w% A - //释放帧缓冲的内存
! K* V& f0 [* s. {# P& X4 P - k_linkQueue_release(&queue);
2 u, P1 Y$ q/ t6 W3 j - //释放寄存器映射! i. i& m( _$ h9 V8 Z. Q; }# t
- iounmap(R_CHIPSIG);
+ O" u9 K) }& E% j' T. e* { - iounmap(R_CHIPSIG_CLR);9 w+ \$ q( e+ r8 l7 @, N- U
- cdev_del(protocol_cdev); //删除cdev1 b- e" S$ V! v: d! M
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号, `, `, Y5 F: Q2 G: J' [; j+ P1 c/ z
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
) V S& t8 \: E" Q - class_destroy(protocol_class); //销毁设备类$ Y& m8 x% S8 q3 T
- printk(KERN_ALERT "exit success\n");$ m% v3 `+ u- {- P/ `# Q
& `! y8 m4 X h* b* F: t& f+ v+ U- }
6 v& @, Y9 e J+ ]) |$ U - //驱动其他部分省略
复制代码
: e6 [4 k- X- e( P. f# h& _8 Z
5 q* u+ D: D1 v' d% _% d. r+ w) f |