本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑
# {0 |5 M# P) ]- j; X: }6 q" ]& F* b: p
项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略6 X/ ~7 T7 U% K, d$ H' x1 }
- g; O" B9 L \. g% D3 N6 B. o
- //引入其他模块函数和变量* t2 g( `& f3 {3 V
- extern Ping_Pong_Buffer res_buff;7 r( j2 q! v y7 p, ~/ Q+ \
2 y0 t+ T8 E ?7 @- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列
- n% |* ]5 o9 R# v, a4 Q f - extern void k_linkQueue_release(linkQueue *queue);//释放链队列
0 u: l9 R5 ^* Z: F& F# \, v$ { - extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据' `5 \" o$ ^5 R- }7 l- T
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据
$ x0 o6 v) \* ~6 y - ) d; w0 m2 x% M. `
- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化# n- K) l7 k3 V5 ^' [, j
! @5 |% ~3 u. K( h. ~0 `; R- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1
( k# p. o) c! n5 a2 h! b - //设置主从设备号6 `3 c3 [ ?3 o: F4 q: v* `& p
- #define PROTOCOL_MAJOR 1/ b7 X" ~( F/ ~( j! A$ R- F/ e* K
- #define PROTOCOL_MINOR 0; t5 D _' _2 m. G4 q" I
, x' M, A8 @8 L# D1 U* ]
# n, T2 @8 `6 E8 m- . K7 g; J$ u1 Y Y' V: ~4 s
- //定义设备驱动的名字或设备节点的名字
: n% ^: \3 |/ J" P3 ^1 Z - #define DEVICE_NAME "protocol_driver"
3 Y& K0 M% @5 ]# U) I+ y# |
/ x' c) q9 u3 F4 B g/ b" m
) n' p* S( y" d- //定义全局的循环队列作为数据缓冲区
5 s1 E$ I3 o t V& ?" e- K8 R4 x - k_linkQueue queue;
! Z6 G0 a) {# A' C0 R8 C, w - ! N9 t0 E% v2 w' ?
- //寄存器地址映射全局变量3 {! L8 r+ m. I* \
- unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器- Y) Z3 Q6 v, [( v) {+ {
- unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器* A6 m" F5 I7 ^9 Q6 M
% D+ x8 l) b" @! p/ S3 ?! _' B- //物理内存映射全局变量
1 ?& }+ _4 [. M4 |% `# y - volatile void *mem_base = NULL;9 U. S" L, k$ Z, u/ n4 ?) o
- volatile unsigned char *cur_buf_ptr = NULL;! n* }' \3 f5 h$ J$ _* Z' }
- volatile unsigned char *data_ready_ptr = NULL;
* b/ a; U2 j' M) B- y4 X
' x) k3 z% U- S# V3 m* U3 W- ; [# S" H5 J; s6 W( [" ]& D
- - i/ X9 c# H- G3 E7 I3 r4 O9 y
- //定义读数据等待队列头,IO阻塞
( s0 O" M4 o9 s$ t+ x" ? - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);
: d s) z7 g* @& a
6 |$ g' f& M" z- //定义原子变量
: s7 p3 s j8 [8 @; K1 @0 N - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备
, Q, ~' s7 p" n) |+ B' a8 n6 ^$ j
; {9 |# h- J, t0 Y+ @0 ?- 0 S9 I# S+ V& Q
- //定义设备类
" }. }* h+ [$ ?6 P - static struct class *protocol_class;
! }6 {+ a& P% I6 F& V6 @4 Z0 ~ - struct cdev *protocol_cdev; I, B* D. P. a! g5 A
- dev_t protocol_dev_no;
% k7 }, y+ q, C/ g: h" A6 i - ; C8 D% ^3 D' B9 }7 Q6 p( t
- /*定义tasklet和声明底半部函数并关联*/
6 ]" x3 Y* J& }+ T/ h - void read_data_tasklet(unsigned long);
; c" a& Y0 E0 F! C* L( _3 O0 x2 }
$ Y) [* Z" V: u5 A- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
) G' O+ Y6 `+ L/ m# m - //将CHIPINT0_tasklet与read_data绑定,传入参数04 T7 D# b. q5 i# n
" v( v, V$ o3 Y, ~- /*中断处理底半部, 拷贝内存*/* ?7 Y) Q# E) `5 i- z+ O% |
- void read_data(unsigned long a)
. C6 P6 _) H h, |! C - {8 ^1 R5 z/ ?6 J- Z& M" Y9 k3 G
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1
1 h- b& }9 M0 R% U, ?+ z9 @ - {
7 `0 W% H7 s1 G3 V - read_quest = 0;( d% w" H+ Z( k3 `% ]4 h
- wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
) E$ y/ X* h6 u$ I; C% q% m - }2 k# j L3 P9 e. V% d
7 k. g1 b0 D X- } F- ~' w4 g9 q2 I7 k
- ! x. E( ~7 ^# x7 g0 ?
- /*中断处理顶半部*/
. f6 a9 q- ? M" n8 V3 C& e6 j - irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)
( S* F2 Q- }: p) X8 ^( \6 d - {7 o. P6 X, I0 v+ c
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样, F7 p- J- M0 D' x- m. m) e: j
- volatile Buffer_Type *next_read;: F8 o6 R( d( q( |
- //如果DSP数据已经ready) O- M- \- G7 L1 o
- if(*(res_buff.cur_buffer->data_ready) == 1)
& ^; D5 V) l( \, [6 [" x- j* Y7 t - {. O2 s. S0 m; E$ L' }) x
- if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer/ G, D( N2 x) r* f5 B4 B0 t
- {
1 W U9 ^, {7 Z* s8 g/ o) y+ e# z - next_read = &res_buff.pong_buffer;//下一次中断读pong buffer ?) x6 o6 b1 i( l) u5 `
- //printk(KERN_ALERT"read ping\n");5 l5 \0 u0 ~& y7 @( T
- }: w, G8 l0 w. {6 ]( g
- else
; B9 p; ]; N% s2 Z$ n1 j( x8 j4 L - {
# r# s: P7 u: ]! ^4 w( | - next_read = &res_buff.ping_buffer;//下一次中断读ping buffer$ a% k S/ t$ J ]7 P
- //printk(KERN_ALERT"read pong\n");7 Z8 T" O S6 C+ e0 q
- }
" l# P6 D2 c: A/ q2 a2 ` - *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer# f$ O* D( Q7 a# |
- //将数据插入链队列: ~6 P( q3 I6 z1 v
- k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);2 a! c( q) L' s1 @
- //标识位都重置1 D9 n4 R; _. B6 l
- *(res_buff.cur_buffer->data_ready) = 0;
0 N) A! | D1 _ - *(res_buff.cur_buffer->data_size) = 0;# y6 w4 z) K1 i$ c
- res_buff.cur_buffer = next_read;
8 `: o4 y4 } q* I/ y: K - }
2 z) g6 A7 k* L - //清楚中断标识
' }/ p" E+ t& c - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status
# b/ Z- W, s6 ]; r* n+ @ - tasklet_schedule(&CHIPINT0_tasklet);//调度底半部
( G0 X. w& v1 g D8 f
4 m0 V1 e7 h! ?# \6 Z0 I! |- ; r- h# X. l- J4 [: w, g& V
- return IRQ_HANDLED;
! k4 X/ H/ f$ R$ r6 }6 `$ D
8 \1 N. q5 e0 E* G9 H- }
( B. R! Z3 l* s5 J6 g9 ~ - , M( _# \& p7 N; R+ [) o
- //文件打开函数
( u/ L# n. b; G - static int protocol_open(struct inode *inode, struct file *file), w. N, {' B; V$ S6 h5 V
- {
3 _# u j5 I, D4 t5 l& \8 w - int result = 0;
4 {& {* p! {& ]5 T4 k+ d - if(!atomic_dec_and_test(&dev_available))
% f# P, G! |7 x- \. z" V# ] - {, e0 D) g; B& v% j% \
- atomic_inc(&dev_available);
7 V6 h9 g' i( Q. ]2 g2 Y& | - return -EBUSY;//设备已经被打开3 w" u5 w4 f, _$ V
- }" `5 G* L- I# N7 N
- printk (KERN_ALERT "\nprotrol driver open\n");4 g P5 J1 Q- K# l6 O) M4 S
- return 0;
& n0 r1 t$ S" d# l - }# ^/ G$ X) ^. q2 @7 R' @% C
- 7 m) V% d( h1 b: k% y& L' }( A& b, `
- //文件释放函数! ^/ ? v" ~, C; y' N; i
- static int protocol_release(struct inode *inode, struct file *filp)6 b& V5 Y0 I, D7 I o
- {
0 F' a) i5 n: E; P, w - atomic_inc(&dev_available);//释放设备,原子变量加1
8 t5 I5 H) l4 j) |- E" x/ [) w - printk (KERN_ALERT "device released\n");6 P; e6 T% ?$ v' k
- return 0;
6 {* P, ]- F8 Z; A: t: S2 s - }' F+ `; }3 ?5 `4 X* u9 V
- 6 m# j9 j [2 B$ ^% m0 J% b6 o. ]
- //文件读函数
' H& O3 b5 Z/ d0 V - static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)
( }: T% K" L. M2 F - {
/ n) x9 @0 J: h: z& C - int ret = 0;
( @0 N5 I) a9 P* V) g - //定义等待队列
$ k* Z( Y a U - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列
0 D- K g# G) y2 C - add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列2 ]) a1 K$ `* M1 z: H
- if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
, o0 G6 \+ m2 ~1 s4 y6 M4 R$ y - {
2 V# {- V" W* y' q) p5 Q: ^7 P - //printk(KERN_ALERT"\nbuffer no data\n");- E! D% N- n; q3 Q1 ~8 y
- //如果是非阻塞方式读取,则直接跳出$ j1 R3 {& H# U5 Q$ {2 Y2 I4 y$ u
- if(filp->f_flags & O_NONBLOCK)
6 j L: s) z4 h; X - {
$ a5 X3 U9 W. ] - ret = -EAGAIN;5 L+ l+ w1 ]* }& ]8 n6 E' O! m0 L
- goto out;
- ?6 k( N6 G% l) m6 a/ m9 q* u - }
$ |4 |5 y4 l; F6 B( z6 F+ s! W - //阻塞当前进程,放弃cpu资源6 u" L9 J8 F9 x8 o3 ^, w; ]7 ?9 V
- read_quest = 1;, ?$ m9 _2 e# ~$ ?, c
- __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠6 r/ k+ P* R( _4 o. \! O1 _3 k
- schedule();//调度其他进程运行1 t+ S" }7 Z5 U5 R
- if(signal_pending(current))
- C) }' t# m0 w" ~. D" F - {
! H( C6 P6 h1 A0 H/ D8 p8 k - //如果是因为信号被唤醒,则返回到系统调用之前的地方7 ?) _7 v; W' l5 G+ T3 y/ q
- ret = -ERESTARTSYS;! I; [9 g% t7 E7 k/ t
- goto out;9 t9 q7 }$ [3 v1 x+ }" z
- }9 o$ R. I0 j' t; @6 P4 r, K5 @- D
- }7 |& |' x3 Z7 X% e' N$ b: Q
- //将数据拷贝到用户空间
8 b: `7 f O( H8 d7 t2 F - ret = k_linkQueue_getData(&queue, dst);
" i! U# ~! C, t4 o# ^- f - if(ret == 0)
! Z+ k3 ~6 P4 X5 c7 I) q, \$ b - {
' z$ @: g/ Z( G2 F - //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);# H) e3 T' L0 e9 A% _) i/ s' X o
- }
& G, h2 t/ d: \7 j) W1 Q - out: z: w7 f; E) W8 Q" t8 B$ {# H- O
- remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列
+ B# j# p- X5 X' S3 `/ t# ^0 Z - set_current_state(TASK_RUNNING);//设置当前进程为运行状态2 o3 |# `2 t1 l& M l
- return ret;: w2 F- ?+ }: W+ k7 D; F
- }
$ w7 I( m1 ~3 q8 Y: G& L" f - 4 M+ K% `$ P4 x T, g
: Q% Z: f/ {' N6 u T0 b: R& e- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)
4 e% G6 K7 o6 l0 C; } - {, H2 X. Z$ u* Q( T4 `6 ]8 R! c
- return 0;
) U, }% W( k8 ^; ? - }
" Z# y' _3 t B/ i - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行
& O7 _ e( L6 L" n" t0 F% P# B - open()、release()、ioctl()协同调用时被调用*/! H. ]* m+ I2 r' `( u. }! b+ i
- static const struct file_operations protocol_fops =5 T K5 ~3 T C* F' Z4 e- f
- {3 \% J6 f+ |4 o* [; c+ X* P; o
- .owner = THIS_MODULE,3 K# z' R4 a5 J5 Y
- .open = protocol_open,* u( U9 a, q) }: E8 F( F4 j
- .release = protocol_release,
# B, g) c% O( t8 V% C& G+ j - .read = protocol_read,% Z7 R1 X7 N k, s& d6 J" `. @$ U
- // .write = protocol_write,! G, I) T* g- C/ p% Y' ^' D
- .unlocked_ioctl=protocol_ioctl,
a0 k r3 z9 p9 T# X7 b - };* {& [/ B: \0 I
' u: h( d* z# Q- /*设备驱动模块加载函数*/; m( T3 u- K% \
- int __init protocol_init(void)1 I- X. d R- v0 K7 V" A& q- D
- {
$ J+ p G6 y6 J: h: d% ~ - int ret = 0;
& G7 Y& Y! F3 X# F6 X' _3 Y3 s - int result = 0;& Y/ N* |$ p- j) | d4 ~1 o+ ?8 ^
- //申请注册设备号(动态)
9 m( l) R1 N5 n' X# w - ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME);
$ o( f m$ ~* |$ r - if(ret < 0)
6 ^2 Q( ] ?7 L( f+ C! B - {
7 D( i5 Y V# x% F- ?( `5 u - printk(KERN_EMERG "alloc_chrdev_region failed\n");
3 |9 l5 X7 _% w |9 B* K/ N - return 0;
" D4 g+ V5 F3 e o$ d6 e - }
$ d8 O$ K2 |- v5 |0 _ - //分配cdev
* g$ `/ B4 D' L5 L# |$ C - protocol_cdev = cdev_alloc();
* R" }, |" Z" `3 e% s; f - if(protocol_cdev == NULL)
4 @+ j! K; W( Z4 v - {
% W0 Z. U5 V; @ - printk(KERN_EMERG "Cannot alloc cdev\n");
9 I' C' \& S) \ - return 0;( u6 |) T! C4 r) J( c
- }
# \9 D$ u' H5 D( f g - //初始化cdev
: ]& `* @. M5 H3 a* h% C - cdev_init(protocol_cdev,&protocol_fops);6 D: }/ m% r$ e# @; q b( z5 {
- protocol_cdev->owner=THIS_MODULE;1 v, D' w& A7 A6 e, D7 P
- //注册cdev4 D. H0 E: o9 c# U8 R* U
- cdev_add(protocol_cdev, protocol_dev_no, 1);
3 R0 x1 g- d) c7 T" R - //创建一个类4 {4 x4 T/ x, X, ?' R7 ?
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);
! a V$ J& f+ n$ P - //创建设备节点3 W# m/ W5 D: b. s4 G: v
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);9 a; \; B! v+ x
-
8 S% `' H: I( t) t9 x7 a -
y: J# h, P' x# u - //申请链式循环队列作为缓冲区DSP数据帧的缓冲区( \* f9 [" c$ p/ A! a s9 E; E
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区4 l8 Z9 A" Z3 @5 z
4 [9 ?; T9 l1 s. b/ ~1 w" T0 E/ [- //映射ARM的核间通讯寄存器8 f8 Z9 s3 n/ Y7 J: n
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);: w0 z, B4 Z8 j" d9 B9 t8 Z/ N a
- R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);5 H; l3 a( k/ N0 S. ?
- //将物理地址映射到内核空间
1 q' R5 u5 {; o* U - mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);* a( M. s- F0 [9 m
- //共享内存初始化$ S! c0 u. ~- H: D* `2 Z$ c$ Z$ ]+ ^
- SHM_ARM_Init((unsigned char *)mem_base);5 w7 N7 e- W1 _) V
- /*申请中断*/( H2 z: S; R+ I& Y8 u
- $ Y. Y+ n! ]$ `3 ]% b+ ~
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);
) w% e8 H( y: ] - if(result != 0)
8 q, E' n& t+ y# i9 {- C/ u - {, ~5 r6 _( E) S3 J
- if(result == -EINVAL): b5 T& q- c" J2 m9 G" k$ F2 k5 b: Z. U
- { d8 {6 b3 ]) Q0 W" v
- printk(KERN_ALERT "irq request err:-EINVAL\n");
5 p7 ]0 r& J" ~) H - }
& ~ o( S/ c) R8 ~8 H6 ` - else if(result == -EBUSY)
9 d8 J3 b( _' _ - {8 _1 N% [ {7 p
- printk(KERN_ALERT "irq request err:--EBUSY\n");* [' M/ Y; [9 I2 o
- }
0 z) j# A9 k3 J9 ` - else
& l7 }- ?6 U1 ^7 L' d+ C - { f$ q% {! L1 A }; w
- printk(KERN_ALERT "irq request err: unknown\n");
# x' b* T# K3 S - }+ U/ Z6 P R& `1 t8 b: e; X
- return result;4 D& F. r2 \3 U( ?% N
- }. {" ]' o6 X. k& v
- return 0;
' g, @6 l# {$ J0 ]% k+ b! n8 Z - }% [) y8 M( Q: g# F7 r& \9 N
$ M" ~1 c" f- ^! Q4 [+ `9 C. w- /*设备驱动模块卸载函数*/
0 I% l8 \3 G) s: z5 I( E - void __exit protocol_exit(void)! i: `! c" y8 F
- {' j: Z" p: [$ ]7 F; J" N" I
- /*释放中断*/
/ j8 F' |- K% B6 e - free_irq(IRQ_DA8XX_CHIPINT0, NULL);
: y7 W( Z. s& I3 Z, H- u( j4 p: r7 G - //释放帧缓冲的内存, G w4 A% a. k9 N
- k_linkQueue_release(&queue);
9 g3 J9 V$ v+ C- t$ A - //释放寄存器映射& [) i2 F0 |0 Y
- iounmap(R_CHIPSIG);+ F" {% j# G$ c3 Z5 b8 P; y+ ?
- iounmap(R_CHIPSIG_CLR); Y( M& l9 e' X4 K
- cdev_del(protocol_cdev); //删除cdev ]5 q* P8 I% P) _$ Z5 g
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号- Y) K7 r( H! P6 N* I" E, u
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点) x* r, O3 S4 P: W8 w: K2 [
- class_destroy(protocol_class); //销毁设备类" P/ ?9 ?/ S" M. \' P! F
- printk(KERN_ALERT "exit success\n");
$ q' s2 _: z I4 z- g5 V
1 _5 r8 N4 G" T c9 j8 E9 o, f- }7 T5 B! S* l# `" c
- //驱动其他部分省略
复制代码
& }/ U& L% F- ?3 E0 w: P
5 t& D( G$ b( n9 V7 A. P% N |