本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑
+ s7 q/ }' A! x: _$ B. a+ Y5 P- ?# T7 ]5 D) M
项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略3 }: k% ^5 i4 j
# d8 e6 h4 @* I+ \& W& Q( V' |- //引入其他模块函数和变量
0 T6 ^' F+ c! Z" `* T" Z1 o5 z - extern Ping_Pong_Buffer res_buff;
! t- J6 M! C+ x: X( X, U - 7 S5 G' |5 R- J" d
- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列: V/ ? S* V- f6 J# k
- extern void k_linkQueue_release(linkQueue *queue);//释放链队列
; O5 y/ X7 Z! j: X - extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据: K) }" L6 u! ~8 ]1 E6 z$ g
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据8 t% E+ y, T& L# Z
( \5 s" F3 Q9 N2 u8 `8 b; L- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化9 i# q& a! z Q3 x) F6 N0 I
- U' q: O! I3 {- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1
; z% H) s" d1 z3 E7 x - //设置主从设备号- }) F& c- q4 B- m# h6 A# M5 Q
- #define PROTOCOL_MAJOR 1
- ^" I+ G1 X' u1 H4 ?. X4 [ - #define PROTOCOL_MINOR 0
7 V( o4 @1 o, K% |" {5 @
+ X0 V7 c/ v, U7 f* E( o1 N: K) Q- 8 p/ f, |2 q. q
- " E# }5 C( X B1 q
- //定义设备驱动的名字或设备节点的名字
5 r, N9 i$ g0 n7 t/ @ - #define DEVICE_NAME "protocol_driver"
2 i) a( L- d) q' W - " P! G, H T# F& G- k5 y, \
- 8 A3 p! M: ^2 D7 L6 i, o! s0 B
- //定义全局的循环队列作为数据缓冲区( Q7 }2 O3 a0 Z# L9 R" W) P
- k_linkQueue queue;
' y2 I& m# s0 |5 X Y - 6 l! `1 L- q y- D; H* a5 V+ }
- //寄存器地址映射全局变量* Q& B' u1 ]2 X3 l: h
- unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器: Z6 j% y! [2 D: L2 t( Y1 ^) E
- unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器# q- o# j) k- b7 ^% o/ W, A
- $ J' j7 L+ m$ C2 I1 M5 |
- //物理内存映射全局变量
" X p+ K6 ?7 C% S - volatile void *mem_base = NULL;) V- ]- p* I. G8 g
- volatile unsigned char *cur_buf_ptr = NULL;
' g* }) j v% w1 _% Q6 I- v" x - volatile unsigned char *data_ready_ptr = NULL;/ V" a8 `: Z7 E4 f% @6 W8 k7 n
- 1 O7 z. \% D4 A) L4 d
- . d0 y! j& @2 M7 |
7 ^' v1 q( @3 o# E- _- //定义读数据等待队列头,IO阻塞
$ P6 b; D, n& a, ?6 n+ H - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);
% K D& {$ N+ d1 t0 |, n1 d
( o& u7 [; `* E" Q' t- ]- //定义原子变量; u4 C/ ^& o7 x/ c; }
- static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备
1 ?5 Y8 y0 v$ ]! l9 _, [
5 X3 ~: E4 b, a! T
# b) k# h/ w Y2 g" N7 y4 A- //定义设备类
4 X, B8 S7 D3 j" D - static struct class *protocol_class;; k8 w6 T" r% X) W/ ?; h1 K
- struct cdev *protocol_cdev;
3 w; O- S/ M3 p* `: r, ^7 b* t - dev_t protocol_dev_no;- A4 p8 f9 j9 p4 E! G
$ L1 z! E) i3 T- R- /*定义tasklet和声明底半部函数并关联*/
5 `0 B$ L, G; q$ | - void read_data_tasklet(unsigned long);
/ K3 e; `5 s% A5 | - 1 x* Y" @& t+ g: X
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
9 E+ Z/ u9 a( n5 \6 S% z, } - //将CHIPINT0_tasklet与read_data绑定,传入参数0, c8 x& E6 D: y: B, y
- % }3 k: o9 R1 f
- /*中断处理底半部, 拷贝内存*/
! k/ [* _6 a2 {4 f - void read_data(unsigned long a)
; X0 H' t+ {8 m, R8 b. T - {# y7 E: r8 P( W+ \
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1; E6 D$ G# M- I( |
- {& N1 P! z) R: K9 C6 g9 P% s5 i
- read_quest = 0;
6 p& q9 J# c( H' U - wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
/ G% z: o) }' h) R! k8 v! d - }: i+ ~8 S: d! i# P# a. T
: V8 ~3 N! _: ?% T& i- i- Q3 s- }% u/ P& w" j* J. x" k1 m
- 0 K! ^/ \9 v# ~: h
- /*中断处理顶半部*/# e! C# N5 x. {* r' |* L3 J3 {
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)
1 e" {; S' G1 V7 s- c& p P- n p - {- [2 d. X1 Z% q, l. t+ z
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
: v" {; [: `3 E+ M) ^4 q - volatile Buffer_Type *next_read;
* Z d$ i, g2 w& H: l - //如果DSP数据已经ready# N( s7 z; U) g8 x1 D# X" M
- if(*(res_buff.cur_buffer->data_ready) == 1)
* b( L- j/ u" P/ D: A: w! | - {4 f, f; S2 q b& t$ a. G5 y3 c
- if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer
! R: h+ H1 ~( Z0 [ - {' w- T8 `0 I( B) P
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer8 ^1 p. t L) t" @
- //printk(KERN_ALERT"read ping\n");: Z8 Y9 H% s, @4 D2 g5 h
- }/ ]; a6 y- l- v/ P8 Q
- else
! w4 A8 d. d4 n! l - {
* }$ B! |9 M( m% i) v# O - next_read = &res_buff.ping_buffer;//下一次中断读ping buffer# s8 Q: [1 K/ z& F% Z
- //printk(KERN_ALERT"read pong\n");5 J" I8 H$ U& W4 L( `& o0 K
- }
& q3 i3 K, f; t( m+ J% s - *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer& I4 d% x6 i" k, u$ N, @8 q# o/ ?
- //将数据插入链队列
1 C! H) B1 C& g - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0); b1 z$ L3 p, \' }
- //标识位都重置% ^$ F# ?' h2 R+ h
- *(res_buff.cur_buffer->data_ready) = 0;
4 s, _. h" P* g5 I* z" K# p - *(res_buff.cur_buffer->data_size) = 0;
0 S2 p( N* R* _; r9 g- i1 Z( x' n - res_buff.cur_buffer = next_read;* P' D0 h8 `9 A% m( y/ ?
- }1 n, r8 \5 n4 d
- //清楚中断标识/ e' L) T3 }" y9 Y2 C+ F! P
- *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status$ b7 \8 i+ }) B5 K9 i7 g
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部
L8 |" O$ S, E, |% E
: P* ?* W/ J# v! k% D6 E
" Q' R; d: d+ F: ?/ @3 H- return IRQ_HANDLED;
# E" u8 A/ \+ q, |9 |! s - 1 L6 V0 x0 S7 \4 E" g4 L, d: ?% ^
- }
Q; g0 C/ A, N& L+ Z - 7 A9 K% u# [' g1 W2 C& g
- //文件打开函数
# ` s0 |! X5 } - static int protocol_open(struct inode *inode, struct file *file)+ u. \ Z: ^. f9 s9 W( I$ x6 G
- {
" x4 Q5 t5 E( o0 t, W - int result = 0;
) Z+ d- x3 V7 |+ b2 U - if(!atomic_dec_and_test(&dev_available))
$ { v: l( W/ J/ [ - {9 U" u5 E* |+ Y6 ^5 e1 E
- atomic_inc(&dev_available);- L' v3 e) T& c+ ^0 X6 C- O
- return -EBUSY;//设备已经被打开( @( \( B* p3 }4 C7 {
- }
- p, o) A/ U; \' Y& Q - printk (KERN_ALERT "\nprotrol driver open\n");
! t, t5 `3 M3 C - return 0;9 t) n# j! B8 F& d5 Z h' ]: R
- }, B2 M L# x. p% Z" }
- / c, {% B# B6 `- e: D
- //文件释放函数) f1 Q% ]. I* b7 n
- static int protocol_release(struct inode *inode, struct file *filp)
& e3 b$ }% ~2 s3 l* {5 ^ - {" s) ^" |& ^# o9 A ^" G& v- t m
- atomic_inc(&dev_available);//释放设备,原子变量加1" Q$ F( f' Z. f3 `9 |5 ~- _" G
- printk (KERN_ALERT "device released\n");: ?- F( z; u& [; ^2 p! s" K
- return 0;
5 s Q, q* m I7 a' e/ e0 } - }
% ?: h- A/ Z$ D$ ^9 e
7 n1 t- Q( U0 `7 v% b- //文件读函数' a6 ]6 A1 ?2 d6 p/ d3 u) K
- static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)8 ?/ `" n7 w7 O$ g& N7 g
- {
. m6 `; U% U' _9 D+ r - int ret = 0;+ Z3 f* ^" z7 y1 \
- //定义等待队列
4 c1 Z1 l* D5 v* J - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列
& k( h) A! } [$ O* E! m* ` - add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
. N+ Y8 S3 h2 o3 x# U- Q - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据# D9 S: |- D3 D' m
- {+ Z' M6 h, H- s3 v! C8 i+ {
- //printk(KERN_ALERT"\nbuffer no data\n");
# n1 { [- ^" e; J' } - //如果是非阻塞方式读取,则直接跳出
0 d' i' @" m t( ~$ y; s9 @ - if(filp->f_flags & O_NONBLOCK)
4 ?6 S7 S1 h' a3 W; ? - {- h: o% [ ?8 O9 D& K; h
- ret = -EAGAIN;, n1 a+ c1 J" L
- goto out;# ^& i# A) _' E4 M7 s- v
- }/ [! U2 R/ L' h9 ~/ L: t
- //阻塞当前进程,放弃cpu资源
]! O5 v2 \/ Q9 i, T& X; V6 _4 ~ - read_quest = 1;
$ `& i( o# |. e4 \) A2 }9 T. M% S - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠' E1 m7 a/ f$ o" Z, O
- schedule();//调度其他进程运行
) ?1 ?6 K5 l' g$ e - if(signal_pending(current))
+ r3 J1 V3 H# w) ?; A2 M$ d - {/ _* N% W8 Z9 A3 J1 r
- //如果是因为信号被唤醒,则返回到系统调用之前的地方) K5 B8 W6 `3 I! V% P5 F0 U
- ret = -ERESTARTSYS;
2 x% v9 A# Y( e9 G - goto out;& F; `+ r( ^7 d1 T4 J/ |% Y0 ]5 E; O
- }7 Y1 y5 F& I, v
- } Z4 S/ j3 `; i2 U: k4 C
- //将数据拷贝到用户空间. f8 o7 o; ]8 b1 q, K* {( _& C' Z, P: t
- ret = k_linkQueue_getData(&queue, dst);
' i2 k1 E) i) v# j* V5 z - if(ret == 0)
" |8 ], p0 s% |1 u& |/ I0 x( R - {
4 I+ L3 N2 N k. p - //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
. F- Z; h7 r8 k6 q - }' K& @. ? k3 I/ W4 j& j k. Q
- out:' U& }5 P2 C. k
- remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列; b0 R2 g4 N" S, ?, r$ B: x: P
- set_current_state(TASK_RUNNING);//设置当前进程为运行状态
- n/ B. R5 z5 ~! j6 [, }% A, n - return ret;
/ w& V; n; M$ V% j& I5 o. Q2 M/ F - }
. Z: q# C5 j; m4 b5 [8 U4 M
5 F* S& f2 V4 l8 E- " ?' t4 A, R5 B
- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)
9 z# Y: G1 M4 {- C9 T - {$ ~1 ` v$ n O; j! s! z
- return 0;& k4 ]0 H. m' R% @5 q
- }; @( F6 u$ K# n* c! \1 Z( a! [
- /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行5 Q# ]( A# G7 S
- open()、release()、ioctl()协同调用时被调用*/. p: D$ V- z# ^" l/ N3 F5 S* E! |
- static const struct file_operations protocol_fops =4 ^2 b7 ~6 I) J: l9 h0 U6 I
- {( `* v9 O# D& v [ L
- .owner = THIS_MODULE,- K# \ |& i7 o- e2 Y
- .open = protocol_open,
; h9 I3 W( V: S! v5 d/ ~( a# t - .release = protocol_release,# V5 L: k Q% r; s/ d" \
- .read = protocol_read,. ?4 q( ^5 \9 f: b s" o. I
- // .write = protocol_write,+ u- ~4 L c, P' `2 b
- .unlocked_ioctl=protocol_ioctl,4 u, l/ a0 W, z
- };
- }# u8 q: W/ |( R& A q9 f - ) H. G# V8 A' ~% j' g ?
- /*设备驱动模块加载函数*/4 D7 Z4 H) S4 i- g
- int __init protocol_init(void)( Y. w/ n" k$ m0 \9 H
- {
2 H: P, V1 \9 h! @6 | - int ret = 0;
o# \, O7 ?- {$ W3 b - int result = 0;3 T3 j) g- F- k) j4 a9 E: h
- //申请注册设备号(动态), Y( j% i3 ?- q* b( E( i
- ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); & V- C& h' M* i5 v0 ]6 x# `3 i
- if(ret < 0), G d& V8 s2 k" S+ u7 M- C4 g
- {* T5 _6 q3 K' c
- printk(KERN_EMERG "alloc_chrdev_region failed\n");# r6 W7 z8 d; k& x
- return 0;: D! c: l) c9 T
- }
S% Y( \* Z+ [/ ?& e - //分配cdev
3 c( ?' {2 O6 z2 L1 U' c, S" D - protocol_cdev = cdev_alloc();6 P& @5 T$ Y4 ]1 e
- if(protocol_cdev == NULL)
( r+ m' O2 @; {9 S - {
. P) {& E- l3 {4 s6 C - printk(KERN_EMERG "Cannot alloc cdev\n");
& V% U! g) }* p0 H, t+ t - return 0;
; e* ^' ^% f4 D, p+ b3 V - }
- g* [; L) M. X2 m - //初始化cdev
: Z5 }% ~/ z0 s5 c3 h8 S# D - cdev_init(protocol_cdev,&protocol_fops);
& J, Y: @- ^2 D: w) q2 P9 E - protocol_cdev->owner=THIS_MODULE;6 _ `& G4 @5 k9 @2 q9 i$ [
- //注册cdev
. L! W' ]0 u% P R* R3 t$ u: J4 |$ X - cdev_add(protocol_cdev, protocol_dev_no, 1);
! l' H' D; ~8 C# L/ | - //创建一个类1 |5 m6 `; s) O* J! j2 H) C
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);
# o( x" w7 Q! i/ P% l% t$ j; R; ? - //创建设备节点# l6 R+ @: t: _) X0 t9 q) {1 G
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);& k7 z- B1 W4 e- a* ~" l3 B
-
1 l: s3 n, @- q+ R - 0 {7 `/ a8 l" v& K& o$ r
- //申请链式循环队列作为缓冲区DSP数据帧的缓冲区* t; N* T3 k$ H$ r! J" @/ ~8 B: S
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区; x/ S. _& X( M/ E
- 5 Q3 {0 x8 V) |! L, F6 r, g
- //映射ARM的核间通讯寄存器. m: g% v+ F7 e
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
. U9 G$ k. _8 X8 f - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);
" A$ ^/ m* x2 [ - //将物理地址映射到内核空间5 x- @& e' K! V" ^6 T8 B# Z D/ H
- mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);
5 S0 j6 ^4 u* u7 x7 R - //共享内存初始化& m6 t: D! S0 u& a
- SHM_ARM_Init((unsigned char *)mem_base);7 b7 P. e3 E2 F9 Q
- /*申请中断*/
9 j! i$ }. B: M
" [5 o: ~/ h, S' B7 g- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);
0 R$ U" H, g/ q - if(result != 0)" J" X4 {6 K2 `+ M a# }
- {8 R5 N [! T# v! [
- if(result == -EINVAL)7 K5 Q4 e! j& D5 d, L5 q1 ?' X0 Y
- {
7 x3 U7 d! p; j9 S - printk(KERN_ALERT "irq request err:-EINVAL\n");
- H# I2 D4 z& x2 m - }; ?$ L8 [/ \2 d* E( N
- else if(result == -EBUSY), E" t" [) Q% i/ ^
- {
: C/ P9 E, n3 [! T - printk(KERN_ALERT "irq request err:--EBUSY\n");1 ]5 Z0 c. h( ^2 C3 b1 T) M6 o' z$ r
- }* q3 B8 r( `& Q, d8 U/ Y
- else
. ^7 i/ }) `! C - {
0 z9 d0 R$ h3 n! c( c+ O - printk(KERN_ALERT "irq request err: unknown\n");# S3 ?5 l+ t' z' T4 h+ w0 M# F
- }
& V1 [! k, p- U! s - return result;! T% w/ {! l+ Y# b& |
- }
E2 q; I3 c1 l* X$ k! l6 v - return 0;/ T6 `/ Z, ?0 j4 `5 C v; y/ f& S6 K0 f
- }) }1 q# {4 D9 P" ?. `! b4 g
# {$ i2 b$ E6 ?- /*设备驱动模块卸载函数*/
- z Q z9 X* h - void __exit protocol_exit(void)
) S" e2 ]& q0 K3 m4 { - {5 k1 K/ B( O( v& F
- /*释放中断*/
& f& |. J+ H' n* w+ z - free_irq(IRQ_DA8XX_CHIPINT0, NULL);
/ h) t- i' o5 v8 W% _9 e - //释放帧缓冲的内存
! u+ B1 U7 j+ R/ t: z - k_linkQueue_release(&queue);
9 v0 J# b. Q3 V4 W. j - //释放寄存器映射) g9 Z! a0 n u4 A; r3 L8 S0 P/ {. g
- iounmap(R_CHIPSIG);
) u5 G, c& H/ j" z - iounmap(R_CHIPSIG_CLR);
/ y( H l4 U& n; I" e - cdev_del(protocol_cdev); //删除cdev6 h8 }7 n$ l6 d' d/ a* V# _
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号7 V- c( b0 W# W: ]9 s
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
- D5 {, ^5 r: K& d - class_destroy(protocol_class); //销毁设备类) k( D" t9 v% r; \
- printk(KERN_ALERT "exit success\n");
4 V# d1 O0 N0 G7 F, z" P
. x8 p7 S1 R) p' ?: N- }
2 z- b5 I7 @4 X! [! V1 v - //驱动其他部分省略
复制代码 & g. ~# A3 n( m
& d& I5 |) `( c6 m! d1 e |