本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑 5 E# J D$ |) d& I5 P1 ^
. h' T2 i5 K2 L/ ^
项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略8 n, q+ ~+ a& I4 }8 I2 T6 |+ a( c
% e; ]- X9 G& n1 S+ t# Y- //引入其他模块函数和变量, [4 K+ A4 U; d" \( H' F+ M% {
- extern Ping_Pong_Buffer res_buff;" y' l& H- p/ N0 [( s# N+ i
- 3 n ?2 s/ r9 L7 g, }# |
- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列- ~/ d) C! v" N: F7 L2 w
- extern void k_linkQueue_release(linkQueue *queue);//释放链队列
/ {- x* c* g3 Y* | ]8 {/ H - extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据
0 K, w; d; E2 p# ^: U8 ]2 K. [9 t - extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据9 K7 k4 o$ C! o$ r+ P D( C
1 W/ `7 B7 w, T \: x, }( R. ^- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化
$ x+ L1 H/ S# R- H9 b- K! Q
7 f$ V3 N) ~! b* s) l g- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1
6 k) c/ ~& R0 G+ ^/ W# n - //设置主从设备号$ h; {% X8 j1 L/ W
- #define PROTOCOL_MAJOR 1
2 S8 w0 y3 Z I) c+ P' g- N - #define PROTOCOL_MINOR 0) S& \# E8 [4 ]" W1 S1 b
- # K7 R( a' s) k. L5 ]6 L: V- s
! e- M/ f: V7 s- 4 ?: m# @, {0 h: G/ s- L
- //定义设备驱动的名字或设备节点的名字7 }: s: ?9 i4 k1 r! W
- #define DEVICE_NAME "protocol_driver"9 y) t# y1 z2 u t7 T* Q8 j& G( x
! N) h G F* r8 V- 9 i# J$ |% ?5 T
- //定义全局的循环队列作为数据缓冲区( {0 c8 k2 f9 F4 u
- k_linkQueue queue;4 C4 ]4 ]' ?( A: F
" I- i/ r& c) H3 k4 w D* i+ Q$ Y- //寄存器地址映射全局变量/ l. s1 J8 F! Q6 k2 K8 e3 e' B
- unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器
5 H( |* B4 n0 I - unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器
, [2 x+ l; Q( A0 U* x y5 c8 n - & c* T2 E" g6 F, p& K
- //物理内存映射全局变量9 K! Q' I) m! O( S8 [9 |$ O
- volatile void *mem_base = NULL;
, V& m) S% C* p - volatile unsigned char *cur_buf_ptr = NULL;
3 \: G. @1 C; [6 _' m. J( f - volatile unsigned char *data_ready_ptr = NULL;
. O& j; J- `2 K; U' `; p% S
. z8 @* O1 @; t# v* i+ `$ ?
- `$ U- d; \- p# [' H
6 F& z1 P6 J* S; y- //定义读数据等待队列头,IO阻塞
' h! l# n+ a1 ]$ M' J, u - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);
& j' C& a7 r$ D
1 h- l! {$ A! O- //定义原子变量
) ~ u T- v8 F6 F - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备4 l `! {; L) v9 y/ o b y& u
: i- `2 I8 k7 N7 ?4 g. w
) N0 d3 T2 D" q8 C- H- //定义设备类
1 z" V O9 c3 ~- A* D - static struct class *protocol_class;/ }/ n. S+ m# J6 Y f& b1 b
- struct cdev *protocol_cdev;, e+ Q' G2 z$ Z; @
- dev_t protocol_dev_no;
6 ?8 ^3 u6 @* X8 |; j$ r C/ p* F
2 _) L. G, L6 o% A% L5 q- /*定义tasklet和声明底半部函数并关联*/
' P5 E2 J; \5 j2 z A* \1 _ - void read_data_tasklet(unsigned long);
( y' z+ v5 {. W' p, V: e4 W5 s
' ^" O7 u4 Q6 ?9 L0 P- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
, p5 `2 [$ E, R, y$ i1 B5 | - //将CHIPINT0_tasklet与read_data绑定,传入参数0
* ~9 o8 ]: C! Q
" q) @' ]$ ?' O9 L; _& ]- /*中断处理底半部, 拷贝内存*/
; m0 t2 ^# k C2 A* { - void read_data(unsigned long a)
" q. a: A$ E Z" K8 \, f% } - {) W" Q% j9 L L. x* ] \
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为18 m- y& J- @) E5 p
- {9 c3 Q( f7 D5 w( V$ B, T4 Q
- read_quest = 0;
" G$ c V7 ?$ a! `5 Z8 r6 t - wake_up_interruptible(&wait_queue_head);//唤醒读等待队列, g7 z. g3 n+ g8 ~, d0 f
- }. n n" q# ?: ^
- " S8 K$ _# Y' {
- }
+ _$ @2 g& G, n! O - : ^% i: S1 s+ u% w! S7 D4 w
- /*中断处理顶半部*/6 s' _ `$ N$ ]- q9 u
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id). w3 S" F! [0 P5 K$ J1 k" i
- {, s' Y1 D/ \, T7 o
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
! P# d5 Q: ?4 c) o. ? - volatile Buffer_Type *next_read;
6 Z- S; u- H. Z7 z* F6 Y - //如果DSP数据已经ready
7 `: q8 u* X0 P" V& \ W' u - if(*(res_buff.cur_buffer->data_ready) == 1)
& N0 b0 {8 L5 d% \$ C - {
8 l/ O8 a8 j+ j8 ^* F7 j - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer
/ B5 T" v' [) a' g3 y8 c) d0 w - {
e( t* [2 Y" R* ^, @+ X - next_read = &res_buff.pong_buffer;//下一次中断读pong buffer
n6 u# @" m* Y2 K9 l% X' u/ ~ - //printk(KERN_ALERT"read ping\n");5 a9 ^$ c+ s. j
- }
" D2 s0 X2 j; E- l* M" ~. V t I1 G5 d - else
3 [' x: B9 \6 o) \! K2 f" g7 j4 | - {, I a3 q7 n* z" b; E, R4 }4 C7 }
- next_read = &res_buff.ping_buffer;//下一次中断读ping buffer1 W6 v. k! V; {) D) C1 N3 D) Z
- //printk(KERN_ALERT"read pong\n");) {& _ |! j8 B; v- ?
- }4 B6 G6 ]! p8 b- Z3 V
- *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer
/ Z8 o5 T1 X P - //将数据插入链队列6 w4 K Y% i0 T8 `! _; F' }8 c
- k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);
5 @; O+ a" Z" Y' N7 S2 P+ P- B' n - //标识位都重置
' X, v: D: z8 f7 t- l - *(res_buff.cur_buffer->data_ready) = 0;# u' C- H4 V4 ]+ `
- *(res_buff.cur_buffer->data_size) = 0;1 T; M% ~* L. s- p* o
- res_buff.cur_buffer = next_read;
- s! a4 _) X' L - }
& R- y+ G+ R7 b7 @: V& J9 R- X - //清楚中断标识
! l. S5 [4 v9 |* v0 W - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status9 I; F, [3 S9 s* p n' D. M
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部
/ A Q [7 M% X4 H" a! e6 l
3 [0 p8 T, A7 e! c
( u" `2 _7 b7 e# U1 I" Z- return IRQ_HANDLED;8 q {2 M0 Q6 c# _7 |
* M. t4 x. |3 L4 J- }
1 ]9 i- E" }% B% b8 {7 _
$ B, U2 c& m6 ?! e0 K J) ]- //文件打开函数7 D5 V/ t( G* j, c- e+ X
- static int protocol_open(struct inode *inode, struct file *file)* _9 i1 U; {8 L: N. E, e
- {
4 G7 o. b) n' Y4 I) Q - int result = 0;
6 _: x, \ I9 k; h0 F - if(!atomic_dec_and_test(&dev_available))7 R/ A8 t4 X' A! Q( @* M
- {9 l+ p: Q/ _& r }
- atomic_inc(&dev_available);
: f: S8 F- Y% S - return -EBUSY;//设备已经被打开
( }6 Z$ q8 x5 K - }
( _, i. X% ?% w4 E4 R - printk (KERN_ALERT "\nprotrol driver open\n");
4 ? Z# z' v# ~7 C* O$ M - return 0;
6 x9 m6 t: _3 f2 J7 s% V - }
. X8 y0 M) T# Y - & R5 f) w, |, {6 ?
- //文件释放函数4 B+ g$ d) z6 P
- static int protocol_release(struct inode *inode, struct file *filp)
! c, I5 T1 ?' c- H - {+ U" Z+ e A# h# S
- atomic_inc(&dev_available);//释放设备,原子变量加1- w$ p& W0 x! @# J
- printk (KERN_ALERT "device released\n");, I% J" z5 q8 r1 ^
- return 0;7 ~2 O/ I8 d& k0 J8 G- K6 M# U3 A0 N
- }9 b- K' D4 [' e- f, U
) e+ ^. J! G: W2 Q$ G4 ^/ o0 e3 m- //文件读函数
) e! V7 ]7 H8 {4 t! y - static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)# L9 Q0 ?) ]1 v5 `) B8 c
- {
- E4 d: y, Q, F' f# {: Z - int ret = 0;& T1 e" k- ?( E0 U
- //定义等待队列8 Z8 b9 s; Q2 B1 K& Q
- DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列9 p3 S% B0 ]9 `$ b7 K
- add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
* J6 a/ U8 v i& @2 a - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
6 @# J3 x& Q. W* G3 ? - {; j7 Q; C. V8 v S% v$ T
- //printk(KERN_ALERT"\nbuffer no data\n");
* `, Y8 u& Z* ?8 S. ]* K4 {# e - //如果是非阻塞方式读取,则直接跳出
, l! g/ H o) P. C% i# P - if(filp->f_flags & O_NONBLOCK)/ O3 i8 ~3 q7 N* i# U6 B+ Z
- { `0 G* b) Y D1 ^
- ret = -EAGAIN;
2 Y$ _. h% Z' `$ ?0 k( e& o - goto out;7 X% [: ^1 L# j' \9 u
- }
/ q4 \' C% K0 h& v3 d) P3 w - //阻塞当前进程,放弃cpu资源
9 B7 I" l7 e4 ] - read_quest = 1;
& n- V) R0 A2 l( p" V - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠
2 _* S1 p! E4 b' b7 I7 n7 d - schedule();//调度其他进程运行
! e2 u& D( [3 n0 v" J0 K+ ?$ ]8 i - if(signal_pending(current))" I5 n2 P. E- Y+ ^3 v
- {, d- D! p/ d4 I. h
- //如果是因为信号被唤醒,则返回到系统调用之前的地方
. O( m7 q. K6 G# G - ret = -ERESTARTSYS;
1 c% G2 M+ W; n+ i4 z, i4 c5 a - goto out;
" X$ n) t% w% n# n - }0 n2 b* I/ W% @1 z, J
- }
7 W! `' l8 S. L5 j3 `: ~! l - //将数据拷贝到用户空间
8 Q5 @- Z. w8 [7 y- ]. Z - ret = k_linkQueue_getData(&queue, dst);
# X; c1 i+ P2 B: q7 L - if(ret == 0), _9 Y- \ B* v( O9 u5 ?
- {
9 g! n% F1 {+ D. q( ^6 l1 \- h - //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);7 Z Q, W$ R& J/ w' B: \% \, l
- }
# l$ t% {. w! X3 a - out:
% r; c4 Y; a* @' C - remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列
: q( {5 K2 q$ d8 p - set_current_state(TASK_RUNNING);//设置当前进程为运行状态' G) O# v1 c( O& J* T
- return ret;
6 u& k" T6 q: P, @" u4 S - }# t' n$ B; {1 n5 q
0 x+ X: r' M6 f1 [; k8 Y" \, s8 O- 8 }! E$ t# M+ J9 G9 t5 j" O
- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)% T2 b3 |! C; Q; y/ u- _
- {( V5 ~2 c. r* u! S2 n" r0 P
- return 0;
0 c/ y* r7 ~* e3 E - }
8 v" ?6 M' [/ l1 c - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行0 G) ?7 M. U. A$ z' ?* O2 r1 m
- open()、release()、ioctl()协同调用时被调用*/( u- N) }2 b b+ r5 }+ c( i
- static const struct file_operations protocol_fops =0 b B4 e0 p7 Y9 F/ H6 T4 ]
- {7 i* c' [1 g+ [. h+ Z9 K. j+ B
- .owner = THIS_MODULE,
7 M# H: d+ R/ ~$ s9 E' S( R5 n, J - .open = protocol_open,9 l+ r# w2 ]& B+ K5 m! T
- .release = protocol_release,/ ~# ~* b. f y* E% Q
- .read = protocol_read,
, k* e* m( Y/ d, H - // .write = protocol_write,
: x* D, G z+ P, I3 ^ - .unlocked_ioctl=protocol_ioctl,1 a e/ c K1 m' U0 H
- };
- Q! `) R# c9 N# m/ q; V/ u
/ a4 Z! L' k1 Y4 e- u- /*设备驱动模块加载函数*/; h6 q8 l ?# G, k. _# P
- int __init protocol_init(void)
1 Y, k2 W5 S% f" ~, W - {
; c0 {5 @8 l2 @, u5 \ - int ret = 0;# g6 o5 }" K5 W( n0 _
- int result = 0;3 o* E' G4 S4 c& X- Q: I
- //申请注册设备号(动态); `) f. D2 U. H' l/ n: V
- ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); $ B' {: T2 q# |5 g$ e+ |
- if(ret < 0)3 M& P, u% [4 R, P7 u0 J0 H* o
- {9 g7 Z6 G+ f& G- L: v; _
- printk(KERN_EMERG "alloc_chrdev_region failed\n");
9 ?8 D4 o5 }* k - return 0;% n3 _ ~# {! ? z
- }
& D+ H, j/ L$ J } - //分配cdev
$ ~ f" \( i+ O - protocol_cdev = cdev_alloc();' _( t, a1 d+ H) O3 f
- if(protocol_cdev == NULL)" A! H8 w. B! H) Y" K# F
- {
4 }& U9 d# b( V- G, O3 l - printk(KERN_EMERG "Cannot alloc cdev\n");/ k4 ^- A( R! R$ b
- return 0;' V8 [% N7 W' j4 s) p$ e
- }0 ^$ ~1 c$ u' }
- //初始化cdev
7 F- r: x# @/ ^! M6 K - cdev_init(protocol_cdev,&protocol_fops);" C8 r6 F& C5 o; x1 `
- protocol_cdev->owner=THIS_MODULE;
5 d! t' i5 h% L7 y, F1 b; k5 O# R0 a - //注册cdev/ L. ]; X, h: u
- cdev_add(protocol_cdev, protocol_dev_no, 1);
3 u P+ W9 R1 O6 ~- { - //创建一个类6 O* E$ L1 c/ E i9 R5 A
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);2 A" D* O! k P4 {! S0 n' ]
- //创建设备节点% n% H0 X9 f0 p* \+ ^, N
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);
% r! l( A8 n1 f+ e# p, [! | -
0 b K3 z4 F+ m6 x; [ D -
4 q" |* [ r2 }& ]6 z - //申请链式循环队列作为缓冲区DSP数据帧的缓冲区
4 l F) v/ Y+ z# D' ^# |8 Z - k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区
, \ V; x8 N/ W7 ]8 {
& j7 T; I y( A {- //映射ARM的核间通讯寄存器
% I, T+ ]2 _" M - R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
, S# Z- x% ]. p$ q: E5 K! ^1 B! w - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);
: L" @- ]4 l8 P* I, e/ z - //将物理地址映射到内核空间1 w1 w3 [4 r' O) u: S
- mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);, }" A+ {- k2 K( i- s: W, ]
- //共享内存初始化+ Y' F5 s/ G7 j, ^3 ]6 V9 j
- SHM_ARM_Init((unsigned char *)mem_base);" n/ C; i* G! W1 e2 v* ?
- /*申请中断*/
9 o. R! Y j7 C! p" f" L - # a' _3 O' y9 n ~6 _5 r3 Y
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);
+ w0 s, q( R7 Z' l3 z" |1 } - if(result != 0)7 M! b. H2 N, A9 x
- {
/ Z/ U1 V5 p2 |! n$ q7 c% a. ^ - if(result == -EINVAL)
! c& G p) J& s - {8 ?+ e( O( C; r: i* v7 z# q
- printk(KERN_ALERT "irq request err:-EINVAL\n");
. W9 S! n8 M! H% r - }: ]1 ^( ^: h) W! a. p1 Y
- else if(result == -EBUSY)
' q( B: m' y& Y$ p - {
0 E# Y/ ^- d' _8 d" f$ s - printk(KERN_ALERT "irq request err:--EBUSY\n");- N2 d! D, S4 t- `: z
- }/ d% |. h% q8 t9 ?2 C8 o: [& F
- else2 E# _' u. s: q4 |3 ?2 y- W
- {
! W* s; |' ]! z* t: p - printk(KERN_ALERT "irq request err: unknown\n");; h* V9 S' ` t) b+ w5 h
- }
2 A9 U* z. j( Y; O - return result;
4 B) b; q5 B+ O1 ]8 W7 u - }
; C- v( M& y6 C& g$ c% e* f5 C - return 0;
$ `1 z. R- D7 w6 E# x# @ - }
4 A! l) X! J$ S5 w' x7 P& Y: T; b - $ d9 ]1 }& r7 S5 u' l9 R: X
- /*设备驱动模块卸载函数*/3 T& m V m. x! F3 ?
- void __exit protocol_exit(void)
4 l9 Y5 e- u& l* U! q# O# |; z - {: j% a: [/ J- y) T, z
- /*释放中断*/
9 h2 b+ Z! z- x. S( o9 ]" R; k - free_irq(IRQ_DA8XX_CHIPINT0, NULL);3 g" m, w! W6 v7 N
- //释放帧缓冲的内存+ M' m' V# y# y* ^
- k_linkQueue_release(&queue);
|. L+ a' f& q/ G; T6 ?2 h - //释放寄存器映射
6 r; @4 U( B( ]9 g% f - iounmap(R_CHIPSIG);
* X- w5 Z% _, K - iounmap(R_CHIPSIG_CLR);. D; t+ _" L8 j7 k5 f3 h. x
- cdev_del(protocol_cdev); //删除cdev$ q# e- I* T( E
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号2 N( a c# Q& K! w; D+ S% j
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点6 P; ~' U. v% J7 m2 {3 H
- class_destroy(protocol_class); //销毁设备类/ [2 F4 ]5 V R D( v @! c
- printk(KERN_ALERT "exit success\n"); P& Z8 h0 I5 }% O" @0 U
- " u4 P8 F/ E: ]# r
- }
4 v" s1 ~1 O8 e: i2 P) E - //驱动其他部分省略
复制代码 ?6 t& o: `9 N! b/ y; `9 H
/ f* Y3 V, @$ e! P/ h! [2 h1 v( U/ Q |