本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑 9 D/ d' C$ A0 i) k
' g3 Z0 E/ U! L1 V ^
项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略
# s3 p, M* I( ~1 T+ e - * c9 A6 i/ X0 d1 ^' M* ]
- //引入其他模块函数和变量
9 r o# O9 Y" d) _2 c - extern Ping_Pong_Buffer res_buff;
, g4 m/ b- G- b# U - ' ^1 h. `8 [9 f' Y6 r
- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列; F7 q) v: B6 P4 W: p( Z ^
- extern void k_linkQueue_release(linkQueue *queue);//释放链队列
7 }, n) ]$ m. C1 f8 b+ ]% c - extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据3 G9 _3 ~, ^! q3 c9 m2 l% V- J. ^
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据0 K. y9 k" T3 h! _
) ~' {/ d/ H6 N, q3 `, Y- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化
0 v9 a6 @1 x+ H( n - / e+ U$ R& k* Z
- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1
1 ^( ?6 a3 }# \/ c - //设置主从设备号
0 B l9 |% a# q* e$ y& h& n - #define PROTOCOL_MAJOR 10 H+ Z5 w! s6 m8 G& `' r
- #define PROTOCOL_MINOR 03 w4 H5 r" p/ L8 _
- " G& j6 }4 N' i' [" q7 \
@- m, \0 t- @, h1 b( e: ]! @7 y
8 L/ y- Z% F1 J3 k- //定义设备驱动的名字或设备节点的名字# a+ k0 w% Q, W% s1 G3 k8 ?
- #define DEVICE_NAME "protocol_driver"
% T9 L* T6 r/ K% h2 w. Q% |2 Z& E9 }
. ?( R0 l# b+ ?3 {6 s: }- : ]8 g' a k" W% ~2 ?1 |8 O
- //定义全局的循环队列作为数据缓冲区
! S+ J* B& l) L. t* x8 r* v" L - k_linkQueue queue;
) g# h7 v7 G, b. r: i1 @/ B
, Y0 u* D( d2 |& Q4 h" z) e- //寄存器地址映射全局变量
3 e8 S+ _, z( z# T- @+ ~4 M - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器
0 R* j- i$ a& ]! Z1 H9 J0 G - unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器2 \* e( c( [, }/ g! S
; @0 g# u# C) x+ H/ I# G7 Z- //物理内存映射全局变量
/ \3 m& a; R9 |+ D% n! k - volatile void *mem_base = NULL;/ V0 X" y5 \, D2 o. P, Y4 _4 [
- volatile unsigned char *cur_buf_ptr = NULL;
; c2 M8 i+ o6 X' C; n( Q8 q - volatile unsigned char *data_ready_ptr = NULL;$ E( q: v1 x1 j8 o! m& c
- $ Q+ Q/ g. I6 h3 g3 H$ C- l* G
/ N: j5 @4 w% z3 m7 c* B1 w6 j- * o5 G' F1 Z2 y
- //定义读数据等待队列头,IO阻塞5 O1 M" Z* N. S5 i9 f' h: R
- DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);
4 D1 K0 ^* [8 u& H4 ~
# ~% w6 d2 T$ k5 `. o- //定义原子变量
( a5 D3 ^) J. b. | - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备
( q1 N E2 v% n: T, g" q
3 d2 p: F+ U, N) g, U# W- [6 \1 G0 t
* i+ U% y6 m) w$ L1 X* L- //定义设备类
' s& s. \3 a$ y1 q - static struct class *protocol_class;
* t& J( m* w6 @; v% R. @2 K9 A - struct cdev *protocol_cdev;+ G; n6 A. [1 X7 U) @
- dev_t protocol_dev_no;
) t% Q% Y! u4 z+ U7 [" P - * |+ ]% d- _: d5 H" d( ]3 e! _4 i1 x- E
- /*定义tasklet和声明底半部函数并关联*/! L% t* r8 ]8 \# I) B0 X" [' v. M0 t
- void read_data_tasklet(unsigned long);
; h* i% i$ }$ H6 o; ? - 6 Q" _. y' L1 Y# p- d# s" r n4 S
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);, s( G% ?, M1 O3 v6 S! }7 [
- //将CHIPINT0_tasklet与read_data绑定,传入参数0
* A9 O* v; c: f( V$ U9 c
, K, [6 `2 T( ?1 B) g! \- /*中断处理底半部, 拷贝内存*/
$ i% Q2 `" o% ^8 ]! l/ W - void read_data(unsigned long a)
! P% J3 V2 p5 _) B( ~8 Q5 ~. R0 E3 @ - {+ y7 Y1 ` ]( C; E9 m7 m7 ?
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1+ e# {' U3 G ?, C3 d* C) S1 f
- {
/ T, q2 M2 J) U4 X" B, R- j" h - read_quest = 0;
1 x& ^# S, ]3 I3 B2 N- { - wake_up_interruptible(&wait_queue_head);//唤醒读等待队列6 A, \( ]/ g$ N* R& O5 K
- }: ^! G# C( h0 U3 R8 `- l4 a
- G7 u6 {' t. I- J- F' o) ^8 e- }
8 D2 ?* {% {0 l/ D4 I& c
, m2 b0 C& Y( N0 e- /*中断处理顶半部*/( O' f& u5 ~7 r
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)
0 I/ O) u# `7 a0 t% s - {2 w' S: E# Q0 g, h B# L, g6 B& \" r( _
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
, |7 t1 U; |7 z6 X9 y1 {8 B - volatile Buffer_Type *next_read;: w( B0 {. U* ]' K* y/ U
- //如果DSP数据已经ready- p3 H; P p; g0 m# X7 f7 E. I
- if(*(res_buff.cur_buffer->data_ready) == 1)) |7 f) f9 u. T) a- T6 ~
- {
' j- B7 h$ s( Z+ z3 B6 T0 e# O - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer
/ v* d# f) l/ ^% g! }( } - {; q7 y h, U/ K3 s
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer% ]+ d4 B( T+ u8 s+ t
- //printk(KERN_ALERT"read ping\n");3 `' F" A2 e! w+ Z+ }
- }7 r; S- t z4 X4 }# Q* ^8 t
- else
+ ]: U( V3 }( |4 L2 ? - {4 X* A6 B0 L5 ?6 x( ~9 ~
- next_read = &res_buff.ping_buffer;//下一次中断读ping buffer
5 \4 O z: M' R - //printk(KERN_ALERT"read pong\n");( B6 B D4 ~7 r9 m+ P5 _( z& M
- }
8 f) ?0 b5 x1 b+ U- B: [% ]. Y2 i - *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer/ g* R7 M Q& I7 x
- //将数据插入链队列$ b V) b) h7 B! S' b+ {: |( U/ L" w3 V0 A
- k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);2 Y, Y o; d+ d u! T N
- //标识位都重置# }: E, y5 m" C
- *(res_buff.cur_buffer->data_ready) = 0;6 W9 }4 t% A! F" G* [0 Z% N
- *(res_buff.cur_buffer->data_size) = 0;
9 x: Q4 G0 B2 o) b# f - res_buff.cur_buffer = next_read;7 L J5 o, c- ~/ m& k n
- }
. C1 Y* Y4 u, `- Z - //清楚中断标识
! C; \$ b/ n# o% E( ^3 _ - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status5 r* R+ V. h0 B) z; Y) J
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部
0 L% l0 z Y! @- p
! {- }; @5 l1 l
! D" u" J1 G" k5 o5 ^+ ]- return IRQ_HANDLED;- U$ C: ] p5 g) P; Q
. k9 w0 v; Q5 J4 ~+ t% z; Q- }& l3 n0 j j$ j9 N
8 f' W; m: ?6 Y) b- //文件打开函数
1 t0 h8 y( h" l; D4 T - static int protocol_open(struct inode *inode, struct file *file)5 q3 U P* I; ?$ ?! I; e. Q
- {
5 w+ {7 |; U$ x - int result = 0;( L+ B' ?+ b' [
- if(!atomic_dec_and_test(&dev_available))
$ {1 m& m3 R/ o - {2 P$ ~5 A+ w8 u8 [+ [% N- {
- atomic_inc(&dev_available);7 h1 _! M/ p% ^1 z0 D
- return -EBUSY;//设备已经被打开- \) M0 F8 C4 i, Z- K4 @* ?
- }
) ]8 d; ?( _$ B9 Y7 J; \: a; p3 S - printk (KERN_ALERT "\nprotrol driver open\n");
/ J; U/ _+ W3 p: n8 g - return 0;" l- X( T, }. E) `: }% L: n# I
- }/ r- K! g/ R6 C" ]. v" t; F/ C4 i# ]
" V; n( b7 E: W. O2 ^- //文件释放函数9 b% m! Z9 w# X
- static int protocol_release(struct inode *inode, struct file *filp)
, y' F) B- B* v0 a8 u( A- g - {
" p( K; ~. r1 l+ i; Y - atomic_inc(&dev_available);//释放设备,原子变量加1
# Z. L- J' W0 q; ~. P - printk (KERN_ALERT "device released\n");
" c1 q/ `4 \2 R, |3 m) d* L - return 0;, k/ S, |% |- H! [. [; B! S' g. w
- }
* W* H$ t0 M+ f1 r# b$ r - ; |0 h2 z% P% g0 r# q1 o
- //文件读函数
% c; m, J4 V1 U6 t3 N z8 E - static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)+ |: `% ?) Z0 ^" O, A
- {- i$ g) h r* G
- int ret = 0;
3 a2 N) U4 q/ @2 e3 Y& t - //定义等待队列
; L g* |* g: b" z& v) @7 p0 x1 V - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列
6 P& ?$ y4 A7 P& r - add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列' \8 X; b6 d3 W9 F4 v7 p! q
- if(queue.remainNumber == queue.blockNumber)//当前buffer没数据
) q5 R+ P2 T5 _, }( L6 D - {4 Y5 W" _7 n- A( I
- //printk(KERN_ALERT"\nbuffer no data\n");
9 E3 l$ |; L- C - //如果是非阻塞方式读取,则直接跳出/ ~, N7 U' W3 H# w0 K( p
- if(filp->f_flags & O_NONBLOCK). Q1 b* y! `7 ?7 g- f+ r
- {/ S/ s& |- z. r5 l
- ret = -EAGAIN;: Q- U! M5 {- Z1 W: w" O- N
- goto out;* @$ V, ?3 c! k: i/ z
- }
- Y: J6 b, C! G. |9 P# f - //阻塞当前进程,放弃cpu资源1 A1 n7 ?; t+ y3 m
- read_quest = 1;1 f7 M) P' X) x8 P1 L
- __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠
0 C: x3 ?! V; i - schedule();//调度其他进程运行
: C- m7 l4 {. ]3 } - if(signal_pending(current))
. P V ?; j4 H( g - {
* f- O" y2 t* c0 n - //如果是因为信号被唤醒,则返回到系统调用之前的地方2 k) m+ \0 a2 p5 ?/ b6 z$ |' ]3 a! X
- ret = -ERESTARTSYS;
- M9 v% X, ^, c& `8 M' l1 `2 T - goto out;
- W9 l4 @5 ?4 i& i - }
, e$ H' C) ^7 C6 O - }
: f1 |; r4 q1 p! b( f - //将数据拷贝到用户空间/ H- e1 b0 y. A$ L8 r" C
- ret = k_linkQueue_getData(&queue, dst);" t& E7 o: h) o K7 ] z4 p' k
- if(ret == 0)
# }" i9 u7 g8 z2 a6 ^$ } - {
/ P: b( |% `9 J Q - //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
1 O4 a5 L. Z8 z! ^ - }
E `5 w) B* @/ N5 x7 q3 b1 f - out:) S6 j# G" p/ S b
- remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列1 w4 Q2 t: A8 b9 R2 Z8 Z
- set_current_state(TASK_RUNNING);//设置当前进程为运行状态
4 M @2 c. Q2 v9 s& Q8 H- D - return ret;
; }8 x8 |+ D3 W1 T! p/ J - }$ I ]2 o; V2 ?; j* |; ^' h
- * t) Q" F! w9 C- T$ B& H
- 1 B& S7 W& Y9 C, h
- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)
1 W' t7 n' L+ u - {+ w+ ]6 I# G r% j4 j1 ^8 E
- return 0;- E' s" \4 G& T/ B
- }+ T& }& Z" v0 h3 t3 m: x
- /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行, k3 j% k0 Y& `1 W
- open()、release()、ioctl()协同调用时被调用*/- g6 c8 V7 r3 K% |0 a
- static const struct file_operations protocol_fops =
; l8 I* d" l$ J. T8 W. b" s6 Q - {9 b; F2 @" j% k5 C2 ?
- .owner = THIS_MODULE,
. | G( z# z7 h( B2 |+ G - .open = protocol_open,) P# b) e- f$ f- g% l
- .release = protocol_release,
6 L. [; D {/ v: \8 C& q8 p - .read = protocol_read,- D; d& k& e [$ o+ Y
- // .write = protocol_write,3 C6 h! t' n% S' x8 P0 C8 ~: O
- .unlocked_ioctl=protocol_ioctl,: @8 J6 f, n. b5 q% e
- };
! S4 E. m& @1 A6 s" g f& B
2 K4 D3 ]& V( }2 i, I1 N- /*设备驱动模块加载函数*/
, S! h/ n, h0 q - int __init protocol_init(void)
7 p5 r; F5 K! U6 y0 I. x - {. y F2 ~0 |5 f- M7 y$ Y# s+ v
- int ret = 0;4 t X% k' s" I3 _6 g& `8 m
- int result = 0;
$ x8 {$ w6 u$ x8 _" G" E - //申请注册设备号(动态)
8 K. O8 Y/ N( ?; O2 z" m - ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME);
2 O' `; ?. ?7 @1 W - if(ret < 0)
- e- p5 ^8 n7 b1 ?' ~/ m - {
: v3 k" g- W' T9 \6 S. [ - printk(KERN_EMERG "alloc_chrdev_region failed\n");
& A- l6 o% r, l8 o8 a/ w - return 0;
' ~8 ^ ?* O4 ?8 A - }
" g* Y) [- A3 H - //分配cdev
: ~0 L& o* r! r/ q. n! g$ W) Q - protocol_cdev = cdev_alloc();
1 F. o6 T7 I; a3 O1 Z - if(protocol_cdev == NULL)
& A& g/ ^* z$ s3 J% V# g9 ^. o+ Z - {
9 }$ e6 i: W8 [# O/ _ n; L' @ - printk(KERN_EMERG "Cannot alloc cdev\n");9 L, |( J! j( Y/ c# h. @( r
- return 0;
/ j _4 Z) u5 T# y& X - }
0 u, B( e& Z, f/ l - //初始化cdev
9 A1 r4 e. O' z8 y( r5 n - cdev_init(protocol_cdev,&protocol_fops);% d3 y3 s, c C, m, I4 C
- protocol_cdev->owner=THIS_MODULE;
2 W4 p2 `) o; p+ C v& ] - //注册cdev
7 B: v2 H' h! L3 n" C% R - cdev_add(protocol_cdev, protocol_dev_no, 1);
7 T" f9 I5 n( G. B7 W& i - //创建一个类' S. v; C4 }* e# Y
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);
/ G e3 S( F9 T - //创建设备节点% Z0 G: |6 B4 ?+ B7 i+ T
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);' V5 l: N( }% _/ z, ]1 ^7 I
- * d4 `% g) p' a2 U
- 0 w5 {9 h! z7 y$ `2 W2 I w7 r0 |( B
- //申请链式循环队列作为缓冲区DSP数据帧的缓冲区
) \! ^. R# m2 f# k- ] - k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区
: A7 h- O. X1 h k% i' Y - 7 F0 \* o& c2 ~/ F4 F- q
- //映射ARM的核间通讯寄存器2 s! I9 n) `( ?, f
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
* ? [& Y+ B m3 N4 L - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);# O, H! M8 N4 Q. G* W( x! X9 n
- //将物理地址映射到内核空间
: P' u6 u& ~& _ - mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE); x7 d8 p2 G6 |4 p* |; R
- //共享内存初始化3 d, h1 C4 x7 D$ [5 x5 Z
- SHM_ARM_Init((unsigned char *)mem_base);
% C: s0 ~/ I' n7 o - /*申请中断*/
: x* K: h$ R9 X8 y
& \; ]+ h( e( R- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);% e' t, L0 L* a/ u1 ?, t
- if(result != 0): w) b3 h5 r0 v2 K$ w7 l) {- {& S
- {
& C1 W# }# X) q8 D - if(result == -EINVAL)) O7 P$ ~% D3 Y: p
- {' z# P, }+ s1 w/ f
- printk(KERN_ALERT "irq request err:-EINVAL\n");8 z, M k5 v# e/ n- t( U
- }' x1 D. p, L0 X3 J
- else if(result == -EBUSY): B' G% G0 |5 Y% n! [$ @
- {
1 |1 u9 Z$ p# a$ D - printk(KERN_ALERT "irq request err:--EBUSY\n");
3 P6 d9 `. ~2 i! i% H - }
) s6 `' L4 w- c, h7 s0 ^; a - else
7 A$ S1 p! P+ J: _& V- Y3 y( i - {
3 K+ R$ q9 k( A4 l - printk(KERN_ALERT "irq request err: unknown\n");7 D9 P+ F5 p4 n- q* E9 ]3 R1 h3 }/ ]
- }" b1 {' D, V" j0 Y9 G4 ]
- return result;( ~4 }+ i3 f4 L: H V! u
- }4 M5 C3 p0 o& o" G- `8 i( M R
- return 0;
+ l0 T/ V* Y9 O' Y2 p! ? - }
, x$ P: `1 U& |6 _
' p9 x* D, H5 I7 D, ^- s- /*设备驱动模块卸载函数*/' \4 n' t% e/ S! D7 N
- void __exit protocol_exit(void)" G3 h6 u3 F/ R# K/ D+ ]! t, R
- {
: p7 D2 Z& W5 \: t1 H$ b& A/ a C- k - /*释放中断*/8 \8 T2 U: _$ E
- free_irq(IRQ_DA8XX_CHIPINT0, NULL);
! t2 w8 z) d @0 I7 U; D- z - //释放帧缓冲的内存+ W& V v$ P U! r1 M
- k_linkQueue_release(&queue);) O) j$ @0 o, o- Q
- //释放寄存器映射
( e: Z* c* v' o, y6 `8 X* {7 E5 E - iounmap(R_CHIPSIG);
. |" z0 n/ s, J K4 `4 C - iounmap(R_CHIPSIG_CLR);
$ P$ A% O8 U6 z' p3 I - cdev_del(protocol_cdev); //删除cdev2 O3 v1 ?, Z+ z- Q& s
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号, V( l( K) q- @2 \
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点- t3 h/ M5 Y* [/ @4 A
- class_destroy(protocol_class); //销毁设备类
5 l% d3 v; U9 S1 Q0 `# ~& ~ - printk(KERN_ALERT "exit success\n");/ {% \$ S; u& \0 B' ^+ S
- + q/ n- H) U- ]5 G* H9 j) N; G$ A
- }
: |2 C! D1 k/ p - //驱动其他部分省略
复制代码 , u+ o. @, F! f) P' D& x- Z
- A9 s: Z; Z* u: l/ G! g2 U |