本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑 & V$ E/ k% d0 b+ U
6 L9 U& ]/ F. y9 t# T项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略% f# J# f8 R1 q: V. W- _0 v
- 9 M* o3 p8 v0 M- P
- //引入其他模块函数和变量
2 \% T# `: z: P: ?+ i6 e - extern Ping_Pong_Buffer res_buff;
) n* m$ \+ T- f8 d% w; I, b
7 l- ~; H5 C. C: m1 L- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列6 P, M3 z4 o. J. H7 U/ m5 Q
- extern void k_linkQueue_release(linkQueue *queue);//释放链队列9 F- ]! R. f4 X7 } r( {9 D3 ]/ a: B) c9 }2 b
- extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据$ }# n, n f, g4 h; T2 `- X; n
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据
q. P- E) S$ N1 e - 4 U+ S. {; D/ O, h" z' p# E! d
- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化7 @1 _) V i! C6 H
0 m" Z9 H" s" K3 K- E% \ `- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1; q! {% [7 |4 d+ y4 J& p6 x" Q
- //设置主从设备号
# [! g. r+ R) Y& x( E - #define PROTOCOL_MAJOR 11 n% z. L' U3 [! f1 v
- #define PROTOCOL_MINOR 0. d% `- E7 U% Q& g% S
3 I, T9 k( D. c$ @5 N( T
: }& I- [; W8 Y+ ]: w. [) B
% ~, |) B+ K0 w9 _# k! W0 m- p- //定义设备驱动的名字或设备节点的名字
9 M1 V: v8 l Q0 @( O1 h6 }; p - #define DEVICE_NAME "protocol_driver"0 c) v1 f5 U3 R4 S2 T
% A# e' H1 x+ \& ^
9 K) M+ B6 d5 P/ @8 I- //定义全局的循环队列作为数据缓冲区 X9 P2 t; c6 K* [ _
- k_linkQueue queue;9 x5 g7 v( t4 h, R' l5 F: P1 p
- 3 [3 N1 j" i& T/ k4 o. ^
- //寄存器地址映射全局变量
) a. Z: Q- [$ N3 w: H% b/ Q - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器$ ], A0 ]% R0 q" @6 q7 o; T! E
- unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器! B( A8 _4 [2 ?; r$ A4 R/ e8 N9 q
- . c* p. V: u- m" J! g
- //物理内存映射全局变量; O' c' U5 {% |; E
- volatile void *mem_base = NULL;7 l: m Q0 m) r) k5 g
- volatile unsigned char *cur_buf_ptr = NULL;
" n& p6 q% A9 L8 Z, @ - volatile unsigned char *data_ready_ptr = NULL;/ i Q8 J) G ?6 S! l2 J
- ) B1 H4 `) O3 H& U
- # R" x+ c4 b* \
- , ]( b5 w+ Q/ W' s' N5 Q
- //定义读数据等待队列头,IO阻塞5 a( }' e: U# s! @# ]/ r; k& l
- DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);
- Q" {# O7 f8 y - + ?" q! K; X; g+ D
- //定义原子变量/ r7 O; G& l7 C$ j# S
- static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备, n3 v! ~" t" \3 A, D+ \
, Q- T9 Z+ n, q1 o7 R, c$ D
( ?& j+ I. \2 i2 ?, L- //定义设备类) @9 M# w9 d9 x/ j) `2 m* n) m" X, L, J
- static struct class *protocol_class;+ O3 B8 |( i* i3 W
- struct cdev *protocol_cdev;
/ p7 Y( E2 D* u - dev_t protocol_dev_no;
3 n6 o1 Q9 R- |6 \. C4 j: M - 2 u2 B2 h* p$ c( p1 N
- /*定义tasklet和声明底半部函数并关联*/
6 A8 h9 ^6 u- e7 t4 l! g5 ? - void read_data_tasklet(unsigned long);
% J7 s A5 `5 J3 q) x - / G( x1 m5 Y, s+ F, @5 Z
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
+ a1 T* y8 v: [% m& e5 p - //将CHIPINT0_tasklet与read_data绑定,传入参数0
3 o) l* `" r- J6 r% a - : w2 A+ W; ~% O3 S
- /*中断处理底半部, 拷贝内存*/
) C# S6 ^+ S& f6 s" J - void read_data(unsigned long a)$ `% o" b( V0 ^& L8 f- w" B# }
- {
1 s* i- c$ V1 r8 V3 K W - if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为15 X; _; q+ ], {, Y* w- |% u, L( Q
- {
9 d2 W8 d# n* E+ }5 {) [, Q, X) D6 X0 z - read_quest = 0;
9 G Z" ]( Y- P& e' {7 x. B - wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
( W% T: P; N2 q - }1 ]7 b! M1 ?. `. H2 a& o+ ~
- - D+ R! `* \6 M2 \2 _
- }
' r- m& S3 J3 Q& h1 _* J
* O% A# Z8 H: q. {4 w- /*中断处理顶半部*/
4 q( T' V+ T9 x6 }/ D. p. d - irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)
* { D# F$ B" M1 b" z - {3 f3 R% J- u$ a8 g3 K/ a
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样6 u/ ]/ q/ d. m7 h% ?5 [
- volatile Buffer_Type *next_read;
: q% C4 m# `. ^% l4 }5 U - //如果DSP数据已经ready
9 l% }" S! a* I7 P+ {* G: X - if(*(res_buff.cur_buffer->data_ready) == 1)2 s! m. n- y6 x* ]% j2 M# u
- {
+ p" T' w8 u4 q( |5 F9 m - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer8 |8 s7 o1 g# g b! P) D# f
- {' X7 S5 G0 @: T( P0 q4 r
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer
$ r8 `1 R5 c! L7 Y7 e - //printk(KERN_ALERT"read ping\n");! w" p3 }) @' Y" T0 r: `. U: B1 D4 L
- }
4 T* t# u+ N. w3 ] i8 K2 x - else
0 \2 e% @. P+ W6 }$ d. B - {
# u( h8 f: Q7 X9 }& n - next_read = &res_buff.ping_buffer;//下一次中断读ping buffer
2 k/ c1 S8 H9 Q! {# O7 |5 V - //printk(KERN_ALERT"read pong\n");1 f! Y5 ^. P" E `! s% ^# l8 C& P
- }
! ~ `* I/ p0 T0 y3 a - *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer: l6 h' a B: T+ u. D- k2 S
- //将数据插入链队列
6 ]$ I+ j5 A4 L; }1 O/ h, ]! Z7 y - k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);' x1 w2 C5 l; g: @+ {& r, M
- //标识位都重置! l# }0 _6 }0 k2 _ [$ I
- *(res_buff.cur_buffer->data_ready) = 0;# R, k8 ]- Q+ t% i+ z) \5 T
- *(res_buff.cur_buffer->data_size) = 0;# G* r6 ]1 H' m( Q5 E$ i m! M1 }
- res_buff.cur_buffer = next_read;
6 F9 w0 k7 h' N: K7 N" d9 p3 V4 Z - }
5 @! K6 \) l6 c5 k4 Y! d - //清楚中断标识
! Y2 w2 ~3 }1 E2 [& n) I) q8 | - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status. n* i5 h2 I. Q4 g* L0 z2 |
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部 7 z; r& D4 O; t) m. u J0 T
3 c8 t$ ]+ {0 z4 y+ h1 R- ( n0 O! Q; `- ?3 S& C
- return IRQ_HANDLED;
0 W$ Y+ W, t/ Q2 S. J
+ `. r5 Q) z* C' t7 N- }
8 L+ `+ a3 Q$ d- i. f; m7 t - , @( \- s0 `& y
- //文件打开函数( l+ E+ R) m3 O2 L/ R
- static int protocol_open(struct inode *inode, struct file *file)
D, w7 ]7 {: ~& y - {
, W, [$ o' f k. |7 A - int result = 0;
- G: I' Z0 {1 M0 s! }5 q/ p7 t - if(!atomic_dec_and_test(&dev_available))" w" f/ `$ V: x; ~6 N6 a! @
- {
/ ?0 Q( Z) y4 c; r. N2 H - atomic_inc(&dev_available);8 f2 V3 R6 h7 Z5 W) h$ l$ q" w
- return -EBUSY;//设备已经被打开
* f. P( E! U9 n( Q2 g - }6 S' i; R% ?, S L1 I
- printk (KERN_ALERT "\nprotrol driver open\n");
?# Z% ~4 c; h( h: F. P - return 0;
. h% n; ^1 N4 p8 u$ W3 \" n - }
3 }) ~% h5 \' U- r - . q/ K; c# x# \5 n! }: Z
- //文件释放函数
6 Q9 z; e7 l- N& ?; ^ - static int protocol_release(struct inode *inode, struct file *filp), k; o9 m4 e" s$ q
- {
% ]" Y! U+ o! J. j3 l4 M. n- C - atomic_inc(&dev_available);//释放设备,原子变量加1
8 Q! E# E4 X7 S, ^9 b - printk (KERN_ALERT "device released\n");
9 }& h6 Y* y u) v% d, Q - return 0;; |; P; X2 K3 ]" w0 V! p3 C7 [
- }
7 b8 Z; {. ?: w. n/ n3 @" {, Y
+ [0 Z2 b# v% _0 t8 A" W6 [& a4 d2 L( H- //文件读函数
, `& C3 Z$ E. J( z* L - static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)
# r1 v2 d/ Q# K- y0 Q3 P - {
! d4 G$ O/ F8 W& Z" k6 u, v - int ret = 0;7 q/ n) o3 _5 o# {5 x
- //定义等待队列 L) O& s) J& W) R+ J- M
- DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列
% N" Z' K" M8 _' V0 z - add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
' ^. G" [( I5 a& x" G" z - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据* k+ i% h" r1 T! s
- {
6 A# i& G0 C; b6 ?2 c( t( o2 s8 t - //printk(KERN_ALERT"\nbuffer no data\n");
" _+ [& I1 L" L6 D- @ - //如果是非阻塞方式读取,则直接跳出" w4 S( A' w6 G7 ?+ v' U
- if(filp->f_flags & O_NONBLOCK)
+ c0 e5 ]5 P& u6 ^- U. Q, Z - {* b" Y# g/ `4 ?, [% Y
- ret = -EAGAIN;
: A2 k+ V( m# S- O - goto out;
4 g; ~1 h( P B& [) z, {* { - }1 X, D1 C" ^* J! j
- //阻塞当前进程,放弃cpu资源/ b: k+ T9 x+ u' G w
- read_quest = 1; |$ u/ Z5 G: J( v3 \" B
- __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠; e. x- B) C9 k# r( t( s
- schedule();//调度其他进程运行
& x0 ^9 B% N* b s4 K& p" V$ t - if(signal_pending(current))# m0 g, Y- j: T& w
- {7 x- I) E0 F$ d: h- a
- //如果是因为信号被唤醒,则返回到系统调用之前的地方
% ~# Q- b+ E8 O - ret = -ERESTARTSYS;
9 O8 l+ e! e0 d' W9 v - goto out;/ d) I# h. O0 \3 a
- }
) a& v+ d* d! S) t! e6 p - }" W+ _) M( `4 r; O! n
- //将数据拷贝到用户空间
7 p; Z) b" e8 `( x - ret = k_linkQueue_getData(&queue, dst);! C+ ], `/ F8 d9 s3 P8 C
- if(ret == 0)
$ T+ F9 t5 _0 i3 ~6 e( N9 g - {$ _! }# F H8 I# t* I; g* K
- //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);* @! d+ Y. U- H2 s
- }
3 s8 ?+ G1 v$ |( ~ - out:
% V$ x. X9 C- s* W - remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列
s0 \& M7 F. ?: ?/ t - set_current_state(TASK_RUNNING);//设置当前进程为运行状态; Z2 i" B, m; L/ B' m
- return ret;& U* F5 M* D$ F
- }% T9 M8 N( K' @ q# l: M* U& X
- ( e) o1 ?$ ] g9 `
& m8 L1 c/ K7 j8 [, G6 F- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)) V$ Z4 a4 f+ U ]
- {
* O* n9 O! Q) } a - return 0;
9 k2 ^" Q, M, v0 l2 z) ` - }
, u7 V/ v) u+ T# y1 V% h/ H7 F; L - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行) L: T! B/ J D: t
- open()、release()、ioctl()协同调用时被调用*/7 F7 J0 Y0 @) E* d0 ?% p5 f9 | h" x
- static const struct file_operations protocol_fops =6 x3 s; a: \# L) ?$ a
- {+ t0 x' |* V0 p8 v' S
- .owner = THIS_MODULE,: Q$ B6 }# G3 `) \
- .open = protocol_open,/ t$ W" _( i# J+ Z0 n8 H. ?
- .release = protocol_release,
7 R# _- M# ]* v4 S, u) r! B! G - .read = protocol_read,
- p ~$ v5 D9 T* N& ?3 p$ T, f - // .write = protocol_write,& Q+ Z! c H# z" g7 x; }5 H' q
- .unlocked_ioctl=protocol_ioctl,4 u/ N1 [: x+ u2 h3 ?% Q
- };6 G; ] W* Q. p: I9 F- W
- : j) t9 D8 Q5 U8 D6 P2 `& k
- /*设备驱动模块加载函数*/& f+ g, l- z: Q
- int __init protocol_init(void)
) [) J9 b4 t# f - {; ~/ i0 o; V8 }$ N, p0 m8 w) }
- int ret = 0;' m" F: X2 S4 C8 Z- y+ q
- int result = 0;8 \5 e# b3 q$ e, N/ O" W) }
- //申请注册设备号(动态)+ X- U" Y$ `7 J" |9 M x8 y4 Z
- ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME);
' c( s8 j) d6 f8 L - if(ret < 0)
( K: k. J9 w a3 Q! u - {" R: Z+ j) P8 s5 @# J; W) _
- printk(KERN_EMERG "alloc_chrdev_region failed\n");8 _ C) g% @6 K% d2 _
- return 0;
2 Z* M) {9 u+ L# n - }) h7 `8 W9 q/ V2 Q2 C; r
- //分配cdev
" M6 x L( c5 L2 ` - protocol_cdev = cdev_alloc();- x5 Q2 ?* x5 q! t8 p3 m L) d& M
- if(protocol_cdev == NULL)' I& ?2 S5 b/ } A) p6 V/ x
- {
! @& i* Y9 k* j$ f4 _ - printk(KERN_EMERG "Cannot alloc cdev\n");
7 h) i3 l' t! b' f% _* h) P+ {" F: x! P - return 0;
! ^& M2 \0 ^* x; i2 o- S' ~ - }
& e6 h' A1 w1 v+ D/ ~4 A - //初始化cdev
7 ~# X6 e! ~$ U T: H; ]2 Y* n2 z - cdev_init(protocol_cdev,&protocol_fops);
4 u# M9 i# n8 r- w8 o - protocol_cdev->owner=THIS_MODULE;
" c/ U8 W5 q& E' d8 Q* p - //注册cdev+ A2 j' J9 L+ @' L2 F
- cdev_add(protocol_cdev, protocol_dev_no, 1); 2 \4 G" [+ H! C- v+ `* Z. D" y
- //创建一个类) F: R9 }, ^5 P& e( W7 s q( V( n2 y% D
- protocol_class = class_create(THIS_MODULE, DEVICE_NAME);
: j4 F- B' K& @; ~ - //创建设备节点
# @7 K: a" P& R( ]8 a. F4 d - device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);" A3 p# c2 ^7 h% {: Y3 S
-
7 F' c* W; v6 k9 r3 _$ q - + o) z4 [" F) O
- //申请链式循环队列作为缓冲区DSP数据帧的缓冲区. j# T- M i5 R* c
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区
8 u: g$ h, _# Y4 A- f: L& ] - ! W% V% O' }' Q) Q! x' v
- //映射ARM的核间通讯寄存器9 O3 y5 u1 j" |! e
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
2 M/ M# `4 b' \' Y$ o - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);
. O I: H4 E: c- x" P3 t - //将物理地址映射到内核空间. ~4 ]; Y- i. Q5 h# G
- mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);
" U* d( ^: ^' B/ ~6 D - //共享内存初始化( p; D" Q4 R+ ]0 J% J9 z- h
- SHM_ARM_Init((unsigned char *)mem_base);4 {* a& D) q/ l$ _2 H" H
- /*申请中断*/: \( ]- k! ?" k3 A0 v# T3 w; u+ X
- 4 ^! x" H. L+ m6 G& S
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);
, q- G* x8 y6 b - if(result != 0) z/ B7 B U7 S+ W
- {# S' F3 N. e: d; g- u8 |8 s/ W, h
- if(result == -EINVAL); ]1 b& p" y( p, c: Q( K+ ^7 z
- {0 g+ `! a. E7 m0 U* |6 V
- printk(KERN_ALERT "irq request err:-EINVAL\n");$ L. b4 x7 x7 ]& E+ r# h
- }
8 }# [" a g& h( W; d# v1 x* L - else if(result == -EBUSY)
4 I# I6 e3 e' n: e' K - {
) L! [4 ?! P$ U- Z8 a7 T5 l - printk(KERN_ALERT "irq request err:--EBUSY\n");
- V8 r3 z3 b3 U. X& j - }( y- `0 j4 q- O3 T" h0 g
- else/ l- M' ^) N+ \
- {
+ {5 \* K1 N% P( ^ - printk(KERN_ALERT "irq request err: unknown\n");
, `; I9 G% w Y2 v- a( g - }
; T2 S2 |# } h% ~7 L8 Q" z - return result;
" y1 a2 W/ w$ x* \: [) D - }# z8 p7 U \# l) h0 y& L& }
- return 0;2 ?7 j4 f9 z `0 e0 V( `+ b
- }
9 i% x8 m# t" R: V/ S. E# X- v9 x
( D7 i" M- X5 _- j- /*设备驱动模块卸载函数*/' F0 `) `! w. E. h: y; x
- void __exit protocol_exit(void)( [7 ]. V- A9 g+ {( G/ y
- {
U! t3 ?# q1 @" |6 `2 R - /*释放中断*/
, N6 V. ]: s8 U - free_irq(IRQ_DA8XX_CHIPINT0, NULL); k( U& V& J. m$ m$ C
- //释放帧缓冲的内存
6 X& {: v9 n) @1 F - k_linkQueue_release(&queue);
/ t) j+ y/ o8 q7 i5 e - //释放寄存器映射
) m% d# a6 z; X - iounmap(R_CHIPSIG);4 {: e3 B( a! K" `- ]7 x
- iounmap(R_CHIPSIG_CLR);
, f, U3 B* H8 q8 M' B- M - cdev_del(protocol_cdev); //删除cdev; B9 N) Q- @+ ?% } b, b- ~0 e
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号
9 q2 E# Q2 ^9 l0 c - device_destroy(protocol_class, protocol_dev_no); //销毁设备节点
. L* |2 P" n, d- q8 n5 y( a - class_destroy(protocol_class); //销毁设备类
% F) A1 V! d. [; j" _/ H1 q% [7 W - printk(KERN_ALERT "exit success\n");: U4 z, d" v+ J2 ]' S
- , \; @3 M* S$ D, E
- }7 r$ \' e n! c4 M7 a
- //驱动其他部分省略
复制代码
& O& z7 e4 b3 w: T4 r5 m! a7 N- Z1 B; v2 N9 o
|