本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑
/ X- m# _5 a4 O
2 N2 m* k! a. ]/ [& u* U* E项目要求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 u$ n0 e* h+ B6 V
+ k) d- {2 b+ F1 G) a- //引入其他模块函数和变量: C* h1 { v$ W2 q* U4 B1 H3 }
- extern Ping_Pong_Buffer res_buff;) p; y+ U4 w3 d( P' S
5 ]$ V; A* N/ c) B" [, d% `2 i1 s- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列/ p- v9 c' B3 S! h& A4 \3 H
- extern void k_linkQueue_release(linkQueue *queue);//释放链队列# e. O( _% j0 I3 v! p6 {3 u c
- extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据. G$ Q3 K' E3 a) w) N
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据 n: d. `3 [+ n6 n
- 2 I0 U- h) }! H7 r! @9 X n
- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化* m I8 ]9 A8 k, X- c2 | w6 ]: p
/ Z; ? o7 A4 v g) \ Y# Z- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1) g3 W/ S* A6 q+ W4 k
- //设置主从设备号
' }' X2 p% Y! r1 H- d3 E - #define PROTOCOL_MAJOR 1
( S* U0 c- B; s - #define PROTOCOL_MINOR 0# M2 _. M: L0 z" Y' w+ Z
% f$ Y g# S9 S. M# R A6 d9 ^
! J9 u& a' k2 N V; V1 F- ! d0 w& a& ?6 y8 I6 _
- //定义设备驱动的名字或设备节点的名字2 P& i- i8 Q. g' ?+ C) Y
- #define DEVICE_NAME "protocol_driver"
I0 F* i4 j3 [! F' K2 y - 9 Z2 {0 E& W' v, U8 I; W3 z* t
4 C) O7 w" S+ Y) H6 ?- //定义全局的循环队列作为数据缓冲区
+ \4 I5 H# c _ - k_linkQueue queue;! m) x; a+ M/ [3 ]
) a2 ? {4 S/ v( }- //寄存器地址映射全局变量8 t! I3 Z, F5 c# f+ x- g
- unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器- |; ]& r r1 `1 O% Y$ a
- unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器
+ I( V/ \9 P. R7 p* Q6 y3 e - ) V3 e; ~9 q4 I6 p" k
- //物理内存映射全局变量. O4 v' v; N7 t2 @/ i5 a% _9 `
- volatile void *mem_base = NULL;! @0 C5 T; @, V# ]+ g6 K R9 v' {
- volatile unsigned char *cur_buf_ptr = NULL;
- l* l! @7 F9 m8 O/ ?0 Y4 T; X" a$ M - volatile unsigned char *data_ready_ptr = NULL;
& f, r8 S6 l5 `) _5 y; a6 {
$ t) k5 e& E4 O: \$ L
. Q0 f/ k( L, `, \
C3 d0 g+ v- S& P$ C- //定义读数据等待队列头,IO阻塞
4 l- i; e/ r: Q. C - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);$ ]1 a J8 |# Z- P" O; w+ j3 e
- ! B- {/ }( j# F, D
- //定义原子变量
+ h7 k) @) }, o5 A [5 r1 ? - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备, g7 \4 g/ V. Z
- : E# i% m' p' q7 u3 ^( k4 l
7 u% G- N' @9 j- //定义设备类$ \0 b$ ~* ^+ s/ f3 ]
- static struct class *protocol_class;
+ ?- f1 n6 h4 S7 b7 | - struct cdev *protocol_cdev;: L6 R, _$ @( ^
- dev_t protocol_dev_no;. l; h$ R& p! W6 w- |/ s
2 z6 a1 T& g$ r$ f7 j- /*定义tasklet和声明底半部函数并关联*/
! ~4 |1 j& z8 P# D7 v - void read_data_tasklet(unsigned long);
2 G# S9 W' X$ U - & [8 b" U% _/ s& q; n
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);' ?' S$ a m5 J6 r" D
- //将CHIPINT0_tasklet与read_data绑定,传入参数0
2 u/ `7 g# O. H - ; ^* `% n: N- L4 s/ a7 g
- /*中断处理底半部, 拷贝内存*/
f& M' B: S' L1 W+ y2 q3 E - void read_data(unsigned long a)& o* F O( g6 M3 b, f9 X
- {
- {/ z }2 q* f/ h" G1 t - if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1
( R& \7 n1 A* X5 r t( ]$ M* Z - {" w9 ~! j% u+ t) F( X
- read_quest = 0;
: I1 o" @5 W% ^; b B - wake_up_interruptible(&wait_queue_head);//唤醒读等待队列5 p! y2 G) o. X7 [# J
- } c% m, V, d) } U+ c
8 \* m; B% Q! ? p- }; ~' _* h, k8 F
- + S" c& q0 Y+ O+ s- T
- /*中断处理顶半部*/3 ]& D5 ?2 Z: s' I# U7 o m
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)
. e8 B8 `7 P5 H0 f - {# }2 `2 j/ J- s0 K2 H
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
* L( T. q& |8 K4 ^3 ^ - volatile Buffer_Type *next_read;! t; z+ R' {% @ v& n
- //如果DSP数据已经ready) u: t: G0 m+ U) r! \
- if(*(res_buff.cur_buffer->data_ready) == 1)# I0 y; E4 w5 _. \& ~" x
- {
3 C/ T+ J( W" T8 O7 l - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer7 B+ e( {' C% N+ }2 {! |" F) G3 o
- {
( X$ S3 T2 g P* J - next_read = &res_buff.pong_buffer;//下一次中断读pong buffer
% P0 z! ?; ` c9 S6 O- C" `3 q - //printk(KERN_ALERT"read ping\n");( v: s- i4 C- g: H
- }* n$ q: B& _- B% `
- else3 e/ B; f. z( }% m4 |* h
- {
$ a5 o& |5 |# ` - next_read = &res_buff.ping_buffer;//下一次中断读ping buffer R, C4 [ V; k
- //printk(KERN_ALERT"read pong\n");
. W# d: W0 C2 C2 y - }( r) B; H' s& C" x
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer. k# L8 v5 f3 e. D
- //将数据插入链队列$ D0 K2 g) U4 k
- k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);
0 e8 X1 @4 |4 G' ^& b, q - //标识位都重置
# A0 \) T3 B% T6 O5 ^6 I+ ~ - *(res_buff.cur_buffer->data_ready) = 0;
: _1 z4 k2 I/ ^5 P3 G$ X; R - *(res_buff.cur_buffer->data_size) = 0;3 y' r; ]7 L- e: b8 v( Q$ |
- res_buff.cur_buffer = next_read;: C3 f$ J* g! c
- }& | C7 ^" f5 E; y6 @- u1 C2 V2 Z
- //清楚中断标识4 Q7 q. Y$ m2 E5 T1 @: o
- *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status
" C. B6 u+ @6 J& l - tasklet_schedule(&CHIPINT0_tasklet);//调度底半部
2 s4 {5 G: A5 `* P' t - 4 Q) ]: K; @- g( ~) y
m( |6 U3 h2 R' \7 D- return IRQ_HANDLED;
9 ^' q# v; `9 A V' F
! _8 Q+ p9 Y+ @* o5 ?" I- }
& c& |$ F' q) v$ p; ?& _, }
6 O: K) N5 J' o; F% c2 c1 {- //文件打开函数
$ D( [& O2 d& S1 ^ - static int protocol_open(struct inode *inode, struct file *file)
b" o* g5 v% ^ - {
. ]% X9 A. Z) l. ~1 l' O2 n1 b3 { - int result = 0;
" O; R( } B y2 r - if(!atomic_dec_and_test(&dev_available))
- b; U, E, E1 p - {1 T1 ^( t. T$ M0 d% e5 b+ r% X) R
- atomic_inc(&dev_available);4 j- U) c' ^. e0 j' N2 v
- return -EBUSY;//设备已经被打开. \1 y7 I3 |9 l
- }$ v- ^+ P& e. I: H) k# F% N1 f# Q5 @
- printk (KERN_ALERT "\nprotrol driver open\n");
$ S& G- ?! h! F2 g& Q% ]; D( L; G - return 0;
4 t: \; y4 J0 q( ]* ~ - }
8 e6 ~% J8 c8 {# `/ M3 f( A - 0 a8 q: m+ Y/ V1 W! n$ l
- //文件释放函数
+ Y' }. A+ [* F, [' h - static int protocol_release(struct inode *inode, struct file *filp)4 S9 m1 I2 T c' ` b3 W
- {
8 {- T( _( |9 Q" u2 F! Q w0 q$ y - atomic_inc(&dev_available);//释放设备,原子变量加1
5 \' ^2 J1 d) Q! b - printk (KERN_ALERT "device released\n");
( }; Z$ e7 ?0 H1 e- Q; v - return 0;- }. X/ }4 H2 r9 ?; Q
- }7 H" f* V0 |* V
- . H- y0 h/ `7 S, x( O
- //文件读函数7 i# X# Q8 ]! j! b- H9 s4 g: K/ `
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)* z9 M! g$ y% k& c- T1 e) U% G
- {
) Q% ^5 b" H4 y/ @# j: d - int ret = 0;
+ a! c5 {3 R* c+ ?0 r - //定义等待队列; ~+ ~+ Q$ g8 R$ ~7 z0 r( c- W2 z
- DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列
) l0 V4 J% J/ N- Z) D: q: r4 B6 w - add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
) h4 ?3 t( {, u( S. w - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
8 X% s; w# o% c9 v' k9 R$ |& W! y - {
+ u; G2 \$ r) C7 i1 F: i - //printk(KERN_ALERT"\nbuffer no data\n");4 Z+ Q0 Z' l' V/ `6 S! m6 r
- //如果是非阻塞方式读取,则直接跳出
0 w% T" z% f2 J" n) x( g - if(filp->f_flags & O_NONBLOCK)
* w' [& j! {# C Z - {
9 F. ^9 |) g* M/ ~2 I5 @- Z - ret = -EAGAIN;! [- a2 Q; k0 @# {
- goto out;8 M8 [+ r' g1 J9 u6 J$ ]" @/ }" \
- }
# ]; b6 V `) B( Y9 V - //阻塞当前进程,放弃cpu资源
# n" q9 o. C; `: e" `5 B2 o9 E" K - read_quest = 1;
# Z1 m8 q& k/ Z. E# {7 v" V - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠- r0 c3 }5 X/ r. D, `8 ^/ \
- schedule();//调度其他进程运行! Z/ f0 t! _% F4 E$ u1 g4 g
- if(signal_pending(current))/ r$ L* M! G E7 f8 c
- {
, ^. a; D& m9 _$ t3 i - //如果是因为信号被唤醒,则返回到系统调用之前的地方
+ u. }; |8 p5 K$ K) ? - ret = -ERESTARTSYS;
8 L; Y! ?( ` o2 z, z/ G1 o, B4 t) X: b - goto out;. ]$ W8 m1 @' U/ G4 F4 n* l& X
- }
1 X# j' o+ e; P3 B6 }# s4 n. j1 _+ ^ - }7 P6 V* t3 f \7 X% {0 h0 r
- //将数据拷贝到用户空间% k6 r2 s1 ^; Q* ^. y
- ret = k_linkQueue_getData(&queue, dst);
1 F7 O; K, }2 W - if(ret == 0)
2 w" k4 s4 [# W0 @. c6 d" f4 N( o - {) N j; `5 G9 X# S/ K- M0 r
- //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);* |; _8 ^8 F% U0 w8 c
- }" l& k4 b. n( K( }+ }
- out:1 g! A+ C( k% \: q9 z2 I
- remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列- P+ j3 t2 X7 A: p, j- k0 B
- set_current_state(TASK_RUNNING);//设置当前进程为运行状态& ?) Y- p2 f+ }! c
- return ret;0 a- h+ h) y0 K# F& ?! Z
- }0 a1 K- H% Z5 S2 @3 w
6 L4 c$ c8 I/ E6 ?" x+ Q" j; D% W
2 N9 P; p6 u3 g- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)9 \$ [6 Y3 W% ^
- {
5 D( e% M1 n5 B$ h: L* o- F% e - return 0;# d e/ l, w6 P, n" T
- }
* A% Z. F- V: e - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行
# ~' b& `* ]- ~2 H: G - open()、release()、ioctl()协同调用时被调用*/
3 w D& h$ N8 i1 F+ a$ ? - static const struct file_operations protocol_fops =
$ V: l: z( I' C% B8 r2 P - {
b% r' P7 h- J7 A; p: @" C - .owner = THIS_MODULE,- P% G. a% S- v, G" l
- .open = protocol_open,
, Z) V- a" ]# Y _ - .release = protocol_release,: _2 m4 X) c" e0 Z$ o' j
- .read = protocol_read,
! \ M5 Z4 @8 h- g$ U( O - // .write = protocol_write,
/ A5 S" ~2 S. o* G& k/ F - .unlocked_ioctl=protocol_ioctl,
3 \) I) M2 ]3 p P3 t4 T - };
d3 b2 g' T: B+ ^- D
3 S w1 ~3 o7 f' \; ^% Z L- /*设备驱动模块加载函数*/& Y( Q& s: ?: Z; {1 A1 t
- int __init protocol_init(void)$ y8 B; ?: R$ K8 P
- {, w6 m( [8 N: h" I( v
- int ret = 0;2 D! D: p. Z- m5 x6 T {
- int result = 0;
0 K. D6 B6 }/ `: S% J, |, @* [ - //申请注册设备号(动态)0 ~( r0 @2 g2 h% r F) @
- ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); 5 o Q2 p" h% B! v: r$ l6 E
- if(ret < 0)
: ]/ B$ c2 E3 e: o c - {
4 F( F! x& U+ N - printk(KERN_EMERG "alloc_chrdev_region failed\n");: L: V2 f5 V" O; W K8 Z# B
- return 0;3 P7 n% q; Y8 q7 E8 H) {+ T- [
- }
. u3 ~& o& z4 t( ?( E - //分配cdev1 w. i7 Q1 c. b5 n1 P
- protocol_cdev = cdev_alloc();6 D% i+ k X' z& ?/ H
- if(protocol_cdev == NULL)2 z0 ~3 C' {: j9 d2 j
- {
0 s0 L& X# G6 g% T8 G - printk(KERN_EMERG "Cannot alloc cdev\n");
7 R8 F, v! H2 g2 [ - return 0;
! \& A6 g0 {+ o6 { - }
+ T [6 r% t5 X+ |: t" @ f$ h - //初始化cdev
- l9 s' y# P0 a6 f" d6 Y9 M - cdev_init(protocol_cdev,&protocol_fops);) l, Z2 O+ F) M- Y6 a! }2 }
- protocol_cdev->owner=THIS_MODULE;
" r4 D( I' _- C# b - //注册cdev7 D6 J9 g( Z+ i9 t5 |6 n# z/ X
- cdev_add(protocol_cdev, protocol_dev_no, 1);
) B& K* `! a! S - //创建一个类4 e3 G( T' z* E: |) {6 ?
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);
! q" ?! P. {/ j( ] - //创建设备节点
: N" L, M% h* p* n2 T2 H: m" x+ { - device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);
% P( r! ?7 n' J -
' u4 ~- `# B6 M! ]' h4 H" Z - & ?8 a, h/ t) Z. h1 p
- //申请链式循环队列作为缓冲区DSP数据帧的缓冲区9 v8 ^7 K4 |8 s$ ?$ i
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区2 f! {# z+ U9 L o2 a6 s
+ {$ D0 D" B: _: u a6 n- //映射ARM的核间通讯寄存器6 B' k6 b ^8 k- ?- Q( V' T* N# J
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
. Z: k5 a) U- q( j - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);6 Y2 t6 h% e" n8 J; c
- //将物理地址映射到内核空间
; n5 [1 x. ]4 j) R - mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);0 b5 }& N6 ^# U8 {$ Z! l
- //共享内存初始化
! L. ^1 Q/ `6 g2 h - SHM_ARM_Init((unsigned char *)mem_base);
( A# N2 o9 Y$ c2 c - /*申请中断*/
. X; i9 z0 X$ P' l) Y0 ]* o
+ e6 x6 N; ~3 ]) z* d' |; J- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);
3 C; q9 l: {. D' h) b' x - if(result != 0)
0 u! I: Q& z, M8 M) z' C - {
& k% [! d, D/ r1 y. m - if(result == -EINVAL): s0 w# s4 u0 I: W2 W1 m0 Y4 D
- {2 ?. j" f$ m* j% o
- printk(KERN_ALERT "irq request err:-EINVAL\n");9 l5 F9 L! k7 q
- }
) R! g* L, d+ a - else if(result == -EBUSY)
3 n" \$ y, z" e, i/ P - {1 g' b% i w0 R
- printk(KERN_ALERT "irq request err:--EBUSY\n");
( m3 S6 }% |+ | - }
" Z/ [( Q5 g& A# e - else
`1 d6 Y$ ^" X/ s6 G! n - {
: j& I! K* _' D. L2 v7 S% U - printk(KERN_ALERT "irq request err: unknown\n");
, p' J7 X6 Q: f; ?4 h - }; k2 z% N2 R4 Z4 s, [
- return result;2 Q: H% w2 D% I# t# G8 L3 N" J
- }
' R& Q) \- q- ~) [( n; p5 S6 q& c - return 0;9 h t( f. k& B/ Y
- }
4 N; A# {* f+ y- r& J% X+ r) k4 Y
+ S l9 {; `. R# _- n; Y- /*设备驱动模块卸载函数*/
0 D g$ N9 b. E$ d% j - void __exit protocol_exit(void)
3 v: c6 j) ?0 U: e; ` - {5 a% v% d. n6 |$ }* S/ l
- /*释放中断*/
- r7 @) f' c7 u3 E6 s6 B - free_irq(IRQ_DA8XX_CHIPINT0, NULL);4 T3 d/ n i. o, b: W
- //释放帧缓冲的内存
0 s- c# C, L& c - k_linkQueue_release(&queue);6 F& f* W& W& b
- //释放寄存器映射
0 p4 a, @ b# g - iounmap(R_CHIPSIG);5 Y; d4 y; M$ C) z: d
- iounmap(R_CHIPSIG_CLR);
. k! E0 K- c6 | `. K - cdev_del(protocol_cdev); //删除cdev) _* @5 J) \& r$ O
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号! R2 W+ x7 S" R
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点( l4 t/ b# k9 a& M5 W% a! A
- class_destroy(protocol_class); //销毁设备类$ I5 h/ @* X) K1 ^! V K t$ L: m1 G
- printk(KERN_ALERT "exit success\n");
; t5 X# f9 X- H- d7 b) m
: I2 I9 @3 T- p! m' e( D- }
5 b1 t0 D8 y/ C: D6 V- | - //驱动其他部分省略
复制代码 3 J7 g1 \' A& i& k# Q3 D1 J
0 x+ N x6 F; f4 f7 K# I" X
|