本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑
3 k# g$ S7 G$ u2 x9 m* R9 H5 T# E! t- z+ |8 }
项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略
' c/ f! T0 I6 f7 i B5 |
1 s( E$ @! w2 v3 F7 j5 C# {; f- //引入其他模块函数和变量' R' l9 ~- @8 k5 ? A
- extern Ping_Pong_Buffer res_buff;
6 Y- h2 g; z8 v6 Y, V3 |4 Z
5 E4 u% v a0 k+ {% D( b; m) X& x- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列; M7 h7 V5 _% L/ S
- extern void k_linkQueue_release(linkQueue *queue);//释放链队列/ g- w6 O* v9 d: p; `) ~ E
- extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据) z( {2 @+ e5 e9 p, L, X; e
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据
: V! |# ^$ {: [* Q- z
+ ^# G/ `8 _6 r p( I. a- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化6 {* A# T2 s G( ]
- 7 {2 z4 a, M9 ]5 |$ {
- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1
: I( g; o3 q3 F; f6 Z; M. G* V - //设置主从设备号1 S- L0 k$ Q C# c/ E
- #define PROTOCOL_MAJOR 1
4 G: I& ?6 ~( H; ] - #define PROTOCOL_MINOR 0/ w3 e- W3 C) s$ a5 i4 r
! }3 F1 X, Y( r: H7 k- " w" b: _. q3 q) O
- % ?2 i$ N* s9 ?/ X$ c8 T
- //定义设备驱动的名字或设备节点的名字: F/ y5 z! t @- c; ]+ d
- #define DEVICE_NAME "protocol_driver"- o. b) X- q4 x$ O! W
; H @8 w; m1 ^) x* b) o
8 U- A" x1 K @8 a- //定义全局的循环队列作为数据缓冲区7 z/ o% w- q, h% `8 _0 @2 J% _
- k_linkQueue queue;7 O( z2 }7 M/ ~: \2 g& V7 ]/ E
& T: X7 Y# V: ?' E- //寄存器地址映射全局变量" a3 O& x: y( i' M- Q8 Q% }
- unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器( l3 P: ]0 ?, G' `
- unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器6 V) ^% y: T: d2 c" o' h
- 0 ~; \3 W0 I( t: A
- //物理内存映射全局变量
0 B: J1 g* [! ^) \9 H) Q - volatile void *mem_base = NULL;
6 l: x, d% j ^9 U - volatile unsigned char *cur_buf_ptr = NULL;
( _$ R6 N0 [6 S* `/ Y6 p - volatile unsigned char *data_ready_ptr = NULL;
2 K$ N2 X: C7 r+ m9 g
: u! [; n" g3 e8 Y9 C- , h* J) P6 R+ c: l
" @' s1 m, S }2 V0 W- //定义读数据等待队列头,IO阻塞
1 o$ c- b& s& M- V0 w; C" Y! k* ?1 D - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);
1 r* F z" a( c0 P, S - 6 D* T7 u; B/ e1 r( }" ^5 ]
- //定义原子变量
+ |0 J9 I6 r4 f! j$ Q - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备
6 o& w# K* k o
& k, z9 q6 ~" w. k, d& s- & W& Q9 h' v, C. X# m5 j
- //定义设备类+ I8 [" y+ ^( K* P! A5 k
- static struct class *protocol_class;
. E8 F5 R" i5 I, G9 i - struct cdev *protocol_cdev;
( o( ]3 { q9 v2 e9 w ?8 ^ - dev_t protocol_dev_no;5 y1 b. y+ I2 M) w, v
- j8 Z1 A/ Q2 T0 b/ |8 _: d
- /*定义tasklet和声明底半部函数并关联*/" q* Q8 e* i4 i& y- a
- void read_data_tasklet(unsigned long);
" P- A0 `* Z. @* F4 B, O' M! g - % C/ s3 d! c5 \; u, H4 [
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
/ s |# H1 l `# c) m - //将CHIPINT0_tasklet与read_data绑定,传入参数0; }7 [2 X. a% k( n& s" p5 m
. M9 v; B8 _) A3 J0 ]' s+ ?- /*中断处理底半部, 拷贝内存*/4 h \3 Y9 P0 D$ l, H
- void read_data(unsigned long a)
: M- R4 B- J S - {6 w! O+ E" G; u$ G5 _
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为19 s/ W* W6 j1 G2 |; D! f" `
- {! \% h$ q, y, ?. w2 z( D4 L
- read_quest = 0;0 J- F- U. Q8 g7 `& \& V/ o
- wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
/ k1 r4 o' l+ w/ r% _ - }
$ s. Q: U; d. H0 {5 d) G
1 k+ B/ r! E9 i) Z* `4 o- }
m& P: ] |# ]4 Q - $ q3 p# |- Y$ s; O6 e, k; y) t
- /*中断处理顶半部*/6 A& `- Y( {$ W |; W3 G
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)
& M" n( B6 y, `# l+ ^0 d8 l - {* Z1 b. }, K+ v# E6 w
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
& D5 ]4 r* L6 h" \) o - volatile Buffer_Type *next_read;2 k$ `' r4 R- _; z, y
- //如果DSP数据已经ready
2 }. w# b) R4 f% H: G ~1 ~8 m - if(*(res_buff.cur_buffer->data_ready) == 1)
3 ^4 ^$ F8 V1 K5 k# Y" ^ - {! b/ S0 D3 x5 j( x
- if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer
; p4 R$ k8 D3 G2 X: V - {. ]! F0 Y$ R8 X1 Z- B
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer" l/ J4 ?9 k2 g' E; [5 S" Z& @
- //printk(KERN_ALERT"read ping\n");& p9 {% X7 Z5 F
- }
! y Z6 g% y' s4 B - else2 [9 r. b, K% Y) R$ D
- {7 [$ `! m" F7 s
- next_read = &res_buff.ping_buffer;//下一次中断读ping buffer* P* @; Y; ~ U" m: S
- //printk(KERN_ALERT"read pong\n");# g- `5 G6 }+ b# K Y: j! \8 S
- }. X' K. |3 U, h4 Q1 ^: a
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer6 e; @. f9 t: f! `: U# \
- //将数据插入链队列
: ^* m% i7 _* ] - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);
4 k2 H# m1 Y# y5 }) T) b6 B - //标识位都重置
$ T+ D1 j# W" |+ j9 j2 d; N - *(res_buff.cur_buffer->data_ready) = 0;( j8 l$ B r# q9 C: S- B
- *(res_buff.cur_buffer->data_size) = 0;
" x* Y6 ]: n4 m! u - res_buff.cur_buffer = next_read;
' }3 s" @! J5 G0 G) D& Y - }0 b; L" \/ { u* s. {6 M; u2 i
- //清楚中断标识1 a3 {% ~( Z3 L2 m: S
- *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status
# e. S3 k/ Q! G - tasklet_schedule(&CHIPINT0_tasklet);//调度底半部 * L( x% H; x; i$ v& b
- 8 K9 `, J# o7 V1 M7 t# ~; r- o: T
- 6 c% |2 d$ w' [
- return IRQ_HANDLED;+ J1 A' A2 q2 A% q9 K! ~3 c
- 8 o$ I h' E% }7 `
- }
/ H2 G) P* \( G, z( e0 J6 O6 E - ! z! o; W: @; k, E" C* S
- //文件打开函数+ W- j# h/ I K- c
- static int protocol_open(struct inode *inode, struct file *file)
8 V- P5 t+ ^/ @2 C0 ]6 u - {) q3 Q4 e- A A6 L8 e d3 s3 h3 s
- int result = 0;. v, S5 e, e+ h# g
- if(!atomic_dec_and_test(&dev_available))* o3 f( Y. R- `0 i0 v
- {
5 R! t. B4 d* o% A2 C - atomic_inc(&dev_available);! z/ u# J4 H" |/ U$ t2 B
- return -EBUSY;//设备已经被打开
/ D: H" ^6 A2 x' P0 ]; l3 n' d - }
7 X9 A( [0 ~9 S - printk (KERN_ALERT "\nprotrol driver open\n");
7 w0 }& U& W0 y6 n' i$ \ - return 0;5 K& Q9 {' q& T" ?' S
- }- Y S' s; c( \) O# F) ?" H
1 `: H2 c3 H% I- D: o- //文件释放函数$ a# D! K: N3 F0 _* l: M+ d& P
- static int protocol_release(struct inode *inode, struct file *filp)
9 e$ T+ @5 O$ R- T' K - {0 h; H# ?$ W- L+ c, X
- atomic_inc(&dev_available);//释放设备,原子变量加1
3 r8 r. \5 I7 ^# J$ F - printk (KERN_ALERT "device released\n");
, x# _9 }- l, Q: X* p1 c& B; i - return 0;
! n7 p) g- p# x8 M O# h+ N* G: d. T - }; c/ b. B3 o& m$ M- G9 Q, y
- x+ R5 d! V+ e4 s- //文件读函数
8 H5 o- t% I* J* n% g2 O - static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)* b' S9 _+ e% n
- { ]! ]. w0 |- |( i% M; j; N
- int ret = 0;6 b4 O; M4 G! Z* ?
- //定义等待队列
, u% d5 p! e5 K+ c6 ~ - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列 ~; m5 Y" `2 X |- z; t$ p3 M
- add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列+ W. |) F& h6 l) z% z
- if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
_9 e+ ]( F5 j+ n" t - {$ G3 W) R* C m; L) S1 r$ q \
- //printk(KERN_ALERT"\nbuffer no data\n");
7 l, I+ Z2 R3 Z# o V8 u" R G - //如果是非阻塞方式读取,则直接跳出# w' K! ^( F3 c& W
- if(filp->f_flags & O_NONBLOCK)
! C, ]- q: \, w+ _ - { }$ E0 @. I- h! m! ]
- ret = -EAGAIN;
% |( I6 d5 ], m - goto out;/ O" P9 k+ q; p3 s8 @8 }8 Q1 D% c
- }
. c, F$ R4 q4 ^ - //阻塞当前进程,放弃cpu资源# H6 `# q% S5 J0 M) a
- read_quest = 1;
9 }; s9 A V; P7 i - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠) S" K# A3 s( P4 U2 h' N. S
- schedule();//调度其他进程运行# } T0 k+ i J3 ?4 D
- if(signal_pending(current))
) f, m6 B* x6 z5 F% @: b7 `& s - {
0 |1 o: g1 }4 T5 o# E# ] - //如果是因为信号被唤醒,则返回到系统调用之前的地方
4 x! ^) u$ y7 O- N. p' k U - ret = -ERESTARTSYS;
9 c! k9 R) C9 P8 v5 I/ z+ _( F - goto out;/ a2 R) _2 }3 y6 I' ~$ l# w
- }( E' z" S& _; p# ]! Y
- }3 b2 S. N8 d* K4 S3 S
- //将数据拷贝到用户空间
5 A: c" u% _7 j7 a - ret = k_linkQueue_getData(&queue, dst);0 j7 _8 W2 u- U, g7 R
- if(ret == 0)
; E/ h3 E% P& J9 V. T J, _ - {
. X' g2 n; g! |+ w - //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);1 o, `( [. H5 ~7 e
- }
p% _: n9 L2 b7 L4 i - out:
2 Z2 O& M3 O! G2 u: Q7 \: c: [8 o6 h - remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列7 ?( @9 y. z* \( L& i$ O# Q1 ^
- set_current_state(TASK_RUNNING);//设置当前进程为运行状态
7 H2 o1 b" H0 K6 p0 [* p - return ret;
\# z* y1 g# c! B; B - }- [. i. ?+ n) y9 f: S/ r
+ y; `4 h+ c' G! L; ~4 b5 Q" h# k
3 z) u# {) }: s p( Q4 d; a ^- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)' Y; z8 w* t8 f9 K
- {
# ?) M7 g8 |7 W- l" u# {3 ? - return 0;7 \% U# i7 Y9 }. g: k% m
- }
9 e+ M5 ?' x2 D, o K. x - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行
4 {4 x1 d; Q, D4 u* ?5 ^: A - open()、release()、ioctl()协同调用时被调用*/
9 b( v, }1 X# G% L4 y" m8 Y: H - static const struct file_operations protocol_fops =
+ Y- V/ s; r4 t8 K - {3 {- e! Z. r( N
- .owner = THIS_MODULE,/ B. p2 S$ ]; Y( a P, p2 c& S0 L
- .open = protocol_open,5 \9 z, V# ~8 g2 V1 h/ x8 Y
- .release = protocol_release,3 N3 M3 }5 v& T+ u" b* M% N
- .read = protocol_read,
* `, E/ H. k+ s5 C: _- ?" p - // .write = protocol_write,
" k, c3 r0 x3 f% J9 M) [2 ^ - .unlocked_ioctl=protocol_ioctl,
/ {. s/ @# n. B - };
( L8 i/ r# ], t+ N" L
1 _5 l4 E$ v- u5 ~9 K* y% c% @* G9 K- /*设备驱动模块加载函数*/5 q% K; a/ ~. ^) _
- int __init protocol_init(void): u8 [4 V7 d/ |5 T) B5 ?
- {+ Z+ B4 h2 ?# Z9 p# C
- int ret = 0;8 z# j/ H; F% k2 A2 V7 V, x6 H7 k
- int result = 0;
0 H* i1 f: u. ]. @( q& G - //申请注册设备号(动态)
1 k6 F, F7 C& { |& n - ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME);
* N7 a: q- \+ v( I7 C+ D - if(ret < 0)' a+ e: o8 }5 w5 r
- {4 ^2 R7 r2 Q. D3 s- K1 T% x4 S- r
- printk(KERN_EMERG "alloc_chrdev_region failed\n");% C! a* M( a8 D T3 H9 [" O1 z
- return 0;
( S0 j6 s( F% U - }
; e# Z# X/ U ^) X' k5 s! Z" d - //分配cdev
& o: S* u9 B& n% N) O- ?: G - protocol_cdev = cdev_alloc();
" x) U1 ^, W. g8 G5 C - if(protocol_cdev == NULL)) U. {+ L5 s6 w! b( t! k
- {
5 o4 l" ]+ Y( O/ Y# q9 _3 q - printk(KERN_EMERG "Cannot alloc cdev\n");0 j- U7 [# I: A# e, f ~
- return 0;5 q. \7 Y% N% [5 d/ M j" z
- }; c2 B; l8 f% \) ^. w6 y9 I8 C! {3 R
- //初始化cdev4 p- O/ g- \( F; f1 m6 G
- cdev_init(protocol_cdev,&protocol_fops);
: k! K. D, K: O }, E - protocol_cdev->owner=THIS_MODULE;' P9 e6 q. _1 i: a! |5 P( D
- //注册cdev/ `( U5 o+ n# X @; E; U# q
- cdev_add(protocol_cdev, protocol_dev_no, 1); i; U; H6 a2 b& T" M: t- D" [* C
- //创建一个类
" \2 l" w8 ^' ^6 L% y - protocol_class = class_create(THIS_MODULE, DEVICE_NAME);/ D- i0 P* D0 L: M
- //创建设备节点 q! x# H% y" C' Q8 p
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);
) _. k/ ]# c) Z; V4 a- r _ -
) }, C0 `0 A9 ^8 `( X- X4 j$ c/ k3 z. w -
0 Y: ~, t4 ?0 P( l - //申请链式循环队列作为缓冲区DSP数据帧的缓冲区/ l* j+ {- s& c4 U" A1 u
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区
2 Y7 h0 ]+ @: `; M% B+ x7 _! i
, b. A# F1 C+ q- //映射ARM的核间通讯寄存器
, O% M" F0 I/ P$ P. n6 | - R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
0 v; V3 p. A: a8 J' {9 M" c - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);4 k. {7 f# z6 j$ d& g
- //将物理地址映射到内核空间/ |. ~' H/ z k3 C1 _, u
- mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);7 V* H5 L( |0 B$ E2 ~4 p6 c
- //共享内存初始化
# s6 ?! `. J9 Z5 ^2 x - SHM_ARM_Init((unsigned char *)mem_base);4 x ]5 A* O4 u; F6 M5 w
- /*申请中断*/$ G% B' r6 V8 R: t
- # j/ M `9 l# s( c% K* @
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);
a4 M* @9 l; F: i' Q - if(result != 0)
4 r! z4 ?/ R3 a( L$ ^/ E' J; X - {* e* j8 |2 y. \$ M" d9 i9 J2 n) V. |
- if(result == -EINVAL)/ P% {* E2 s% k
- {
& @* R( L2 B" x$ u! y0 V+ C - printk(KERN_ALERT "irq request err:-EINVAL\n");+ l8 l, i( X3 P. t5 S+ ?6 l
- }
7 S& O# O1 K- i, C4 x - else if(result == -EBUSY)
/ f% w/ |, `: x! Q( |, Y - {6 q8 \9 s+ A: q1 y m4 K h
- printk(KERN_ALERT "irq request err:--EBUSY\n");
; x1 }6 j1 L8 P8 W8 P& C - }9 H B* {8 [9 d4 ?0 o- V2 s
- else. T) @3 N6 _5 r% r* k
- {8 g6 h! D) K- Q% ^* v& e1 J
- printk(KERN_ALERT "irq request err: unknown\n");0 [. f) P) v$ x2 T6 s! y
- }+ S& p: t1 ~+ j% N/ _0 W
- return result;, `* Y+ }; L5 O- i
- }
/ d \5 `4 z/ C8 w: ^! V - return 0;
1 e4 w" X% B2 h* E) b - }
; |% D7 d# Z; x! ]$ Y! p
7 }6 h5 x5 G: s- /*设备驱动模块卸载函数*/
' ~9 m8 B0 H7 Z) Y2 O& X5 R0 f! v' \ - void __exit protocol_exit(void)
3 d3 O% \ x. K1 j7 A - {4 H1 \* q# r0 e+ Q5 f/ p7 {
- /*释放中断*/
Y, |, F( y1 t' d8 N5 D - free_irq(IRQ_DA8XX_CHIPINT0, NULL);
& @3 c7 x4 c& t0 d* n; `: A4 v, I - //释放帧缓冲的内存$ e( H" Z# ~0 l \
- k_linkQueue_release(&queue);
P/ [- v( ` X1 {7 |" B - //释放寄存器映射
u9 z) Q A% f - iounmap(R_CHIPSIG);! z9 {% a1 H% R- B2 x8 g
- iounmap(R_CHIPSIG_CLR);( t- A" {9 d1 [" Q
- cdev_del(protocol_cdev); //删除cdev
$ G: ~* R6 Y- j% } - unregister_chrdev_region(protocol_dev_no, 1); //注销设备号& Z% B- T" b8 N/ i, o+ w
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
" L g* h8 E: G E L( H - class_destroy(protocol_class); //销毁设备类
; P2 _9 [1 ]5 w - printk(KERN_ALERT "exit success\n");' X: ~/ O2 z8 c* t6 S+ N
$ Q# R9 b* A! x9 ^- }' h+ O3 s3 B* M2 v/ Y) E! ?% m
- //驱动其他部分省略
复制代码
+ y! P3 {2 x3 q& A3 r1 j7 p$ R% L) |( p- U- V/ v
|