本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑
1 ]5 i8 G* m) J: b4 b2 @) n; o/ M) S7 }- f2 d5 J) `2 t# A
项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略$ ]. @2 o; M# }
- 0 Q, U$ M, R; {# m& G/ ^; _
- //引入其他模块函数和变量/ |4 ~* ?) }) k* N- [7 `
- extern Ping_Pong_Buffer res_buff;- t0 c, i' n$ s, w- w: Z% Q
- 2 l0 B2 @3 S1 Y: Z& R
- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列3 \7 I* f' X. {5 W; W; X- T
- extern void k_linkQueue_release(linkQueue *queue);//释放链队列 x, A. u( F. R. e/ o( k- M
- extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据! e5 a& g! }% a0 U" Y7 w2 H$ ^/ w+ L
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据
6 D, g% t' j9 @, Y6 L - - M2 [4 m8 l1 ~2 k% c2 Z" T) B& k
- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化
3 L/ A1 i$ w# W# c# O7 ]0 y6 |4 \- g
; g$ b1 ]1 q% Q" S- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1+ a1 V: ]; \( t& V6 x
- //设置主从设备号: F8 m: }! t8 f% ]- b) K
- #define PROTOCOL_MAJOR 1. g" K2 a1 Y# r7 ?$ F
- #define PROTOCOL_MINOR 0
3 {. r S N; n' P8 q
2 `, w+ w" F6 }) n, E# l
( {& V; b, J6 Z \; `9 @- % e- o3 x+ r5 {
- //定义设备驱动的名字或设备节点的名字
. b% b' _6 a( D% Y w2 K - #define DEVICE_NAME "protocol_driver"3 P+ d1 o u) ]+ U
- 8 u8 b* ]3 q# C3 ~% |
- & V! \4 W8 D) J+ M* {/ n S- n
- //定义全局的循环队列作为数据缓冲区+ p7 Q2 j \6 X5 M
- k_linkQueue queue;
( n; v0 c. U6 l. J7 j+ j8 [! A9 ~8 U4 Y
9 q4 d) h/ l/ G: l2 O: P5 B2 U- //寄存器地址映射全局变量/ y/ J, d6 p7 W9 e) V" Z: }
- unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器
4 C6 V$ | R; _2 A8 s7 ^. P - unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器
% b$ x* u! T* q! a5 d9 E
4 w8 X, d' p% I& H; J- //物理内存映射全局变量( Q; N2 n! \6 L- F
- volatile void *mem_base = NULL;9 g' O) ^6 t$ A
- volatile unsigned char *cur_buf_ptr = NULL;
% ?: A! Q* c- c. ]. j; V - volatile unsigned char *data_ready_ptr = NULL;
8 c" ^2 K4 m( l
3 w9 W' I/ [% u5 G- _3 v- & C8 y* o: Z) |) g0 f
- ' v3 ~$ g% b2 F
- //定义读数据等待队列头,IO阻塞, ^' s' }+ ~* V
- DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);9 S7 v, N) N, c+ C. }: s; T8 z
- 4 R4 b8 e: k, \& t8 Z' Y3 Z3 T
- //定义原子变量1 m% b1 }( t& x3 z7 P
- static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备
3 V) U, q. |: k; G# a8 [
$ {& t7 _3 o7 g4 N( J0 V- / ]4 ?; F4 p+ F4 i1 P2 ]# g2 v0 e
- //定义设备类
0 [8 u* B+ |& j$ k! r' g0 n - static struct class *protocol_class;, k. d% n0 s' f' i. {
- struct cdev *protocol_cdev;
8 Y9 \/ @6 ~5 R9 b( g% n - dev_t protocol_dev_no;
* g" k; H/ w7 U. W# S7 u8 l
& J# @1 v6 ]8 c, n$ v4 @- /*定义tasklet和声明底半部函数并关联*/# t m- _) v. x. n: u
- void read_data_tasklet(unsigned long);
& Z% A* E! U0 m+ ]3 g/ R
7 V' W3 _3 _0 [9 }: `8 f: h- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
2 {. P5 ?! U" ~( ]' b* P - //将CHIPINT0_tasklet与read_data绑定,传入参数04 f- s+ ^: y" `; m1 G4 t& e
% r% E5 M$ e$ z- /*中断处理底半部, 拷贝内存*/5 P0 K' Y; S! o4 q' c9 e$ }
- void read_data(unsigned long a)1 o0 k- S# Z* g6 h3 ~& W
- {
' j4 n5 Q6 g V: M. R - if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1) Q9 C0 y9 P% j/ j, x0 B+ w; `. a0 x$ b
- {9 ]1 J U' j) k" J) M/ d
- read_quest = 0;
6 @" T) b3 b3 ~7 s; W' m7 p; p - wake_up_interruptible(&wait_queue_head);//唤醒读等待队列' e/ W7 v8 E* i; r6 X- R; F( V3 r
- }$ y+ U3 b4 q' C5 V
2 H4 K; i' p* L& Q" N* I- }/ e5 i/ x O& O* C6 A# V
* Z1 X: A* s* c. n$ ^- /*中断处理顶半部*/
0 M8 a! X" V4 w - irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)
* f: `- a8 c) b6 c9 a- M - {3 o% N4 y$ r8 B& v: A
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样
5 @1 C$ y' d! b( p" e - volatile Buffer_Type *next_read;
# L* f6 G$ |. D) |: x* N - //如果DSP数据已经ready; X: c$ w, ?$ _3 g8 a) ]
- if(*(res_buff.cur_buffer->data_ready) == 1)' C5 o0 {& S1 ~4 Q# K I
- {
, l; {' _- f$ l# w - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer
+ c% z5 I/ ^* l - {
3 | Q& c* m2 o2 q U - next_read = &res_buff.pong_buffer;//下一次中断读pong buffer8 r) O* i2 D! f( p0 _. O6 D2 k
- //printk(KERN_ALERT"read ping\n");: n1 |' m1 T. }1 x
- }6 Y' n4 y u3 e' u- q' J& r
- else( S* K7 c! p8 e( |. j# g
- {4 f; I# N1 j" Y y6 o0 P& d# s
- next_read = &res_buff.ping_buffer;//下一次中断读ping buffer
" v2 f2 m/ h- I' H9 x - //printk(KERN_ALERT"read pong\n");8 e" {% [3 Y& Q1 G1 N g
- }
$ D: F! S4 X9 S* w% j2 l - *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer
( c! p E+ U& c: x - //将数据插入链队列0 J, [9 f8 ~" ~
- k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);& z2 {2 ~$ s D( g! C+ [7 ^9 V$ M' {
- //标识位都重置; W3 ~% j2 |8 y' E5 ]8 e
- *(res_buff.cur_buffer->data_ready) = 0;
1 v4 ~" a4 B7 a+ [5 [: d5 H2 L - *(res_buff.cur_buffer->data_size) = 0;
8 f% ~( E2 J+ \+ n" g - res_buff.cur_buffer = next_read;5 L" E; p: P( V" U2 p( v }+ c0 z. W
- }
' t7 `- [' Y/ S0 O% d - //清楚中断标识
' _4 |+ K8 a9 @! K5 Z2 e - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status: Y: ?. D7 i' r! A+ G& d8 I
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部 ! o8 C2 x7 z: D4 c
% x P5 o& Z' v3 {- P: b% I2 |6 P# t! E0 @7 t
- return IRQ_HANDLED;
9 b. A% W6 _! ^; G7 g
l& U% b9 z2 _$ p- }7 Y Q- l9 a- l$ Q
; ^& i: i& l, t# c0 H- //文件打开函数# D- g6 B1 P% w: D
- static int protocol_open(struct inode *inode, struct file *file)- `2 G: J1 T- p0 w* _8 D
- {5 ?& w7 x5 v5 a w6 K/ H; H
- int result = 0;1 J& u$ @4 D% q4 L& S; B) f0 U
- if(!atomic_dec_and_test(&dev_available))
?/ X, }% M* D" g+ g$ t9 n2 ^6 [8 t - {7 l9 U, u6 o5 v* _
- atomic_inc(&dev_available);% @2 r+ y" N0 s. M% I
- return -EBUSY;//设备已经被打开4 Z+ U1 |5 t2 m" V' Y
- }
/ \5 z% G. D- w+ s4 I9 F - printk (KERN_ALERT "\nprotrol driver open\n");! ?( ?4 M: d0 L* V: S
- return 0;
/ g( G# U( Z6 C& x8 o! T8 J - }
* {/ J) B- [7 O6 |$ J9 c- _
' v( p. X9 G3 Q# {% ^- //文件释放函数
9 R1 H4 \/ l3 v, I - static int protocol_release(struct inode *inode, struct file *filp)0 v! R, R3 R* |0 x9 C
- {$ X3 _9 @5 h/ n) A
- atomic_inc(&dev_available);//释放设备,原子变量加16 W2 s( E f$ v9 M( Y: i- b) O
- printk (KERN_ALERT "device released\n");
0 d7 h- e9 E0 R5 j6 a& b! o - return 0;/ P1 `7 \3 ~& E! |6 s
- }% C7 S5 C. G( t( _/ I$ R" z
- ' ?2 b, N) @2 u' v
- //文件读函数
+ r) C% Z+ G/ Q* ^4 @* [' x) g - static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)' O n* {* W; W& B, a o
- {4 t$ c' |6 L* h
- int ret = 0;
$ g; v7 C% R6 q% u/ t) s. K - //定义等待队列
. ?/ r6 |0 N# Q( q - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列+ X2 `" G" |2 o3 `- d) d! B
- add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列8 e9 R& u* ?% r' h: |
- if(queue.remainNumber == queue.blockNumber)//当前buffer没数据- |8 H; J1 o0 o A2 p- u
- {
3 E- ~ a" q. G# U - //printk(KERN_ALERT"\nbuffer no data\n");' r. ~5 }8 K# X8 G* J2 {
- //如果是非阻塞方式读取,则直接跳出
' |9 ^5 Q6 F3 Y+ C - if(filp->f_flags & O_NONBLOCK)5 t) H9 l& ~& R# f! l
- {# q% N; _6 a8 C$ F4 v
- ret = -EAGAIN;2 p1 m& M7 _" j6 z. {9 `9 K& k
- goto out; A, _& L8 a6 Y" {# z% E
- }7 x3 e. H8 E& _0 Q
- //阻塞当前进程,放弃cpu资源
; ]: c+ p" \7 [, `2 O - read_quest = 1;
* `: {# {+ z; ^; j6 U! H - __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠. ]* T2 Y6 D) e2 b
- schedule();//调度其他进程运行
* {6 I# R1 F% A' U9 Q4 P - if(signal_pending(current))1 W( f; y5 T8 E! Y3 ?/ m( [0 v
- {; H1 g' | g% d( v1 u
- //如果是因为信号被唤醒,则返回到系统调用之前的地方
- s: }* @+ M5 X2 y - ret = -ERESTARTSYS;) L' t& k B" ~/ B9 U, M& c0 }/ h
- goto out;
0 s$ ]0 y* e4 I2 i) q. z: F4 V - }, s' c6 \3 h$ { D
- }
8 |/ c* s! W! C- y - //将数据拷贝到用户空间
5 @! p: A5 w6 a O: K3 b - ret = k_linkQueue_getData(&queue, dst);
, v& o2 o( L5 K5 D" h0 Q+ h4 S - if(ret == 0)4 u1 k* r) v5 f$ }. x; O
- {6 ^' g- X+ P% q' ?8 }9 j
- //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
2 n: _ p' X$ t/ F5 U - }/ A# i B; I# }4 o/ H
- out:
2 D! S, h0 f9 f8 g& T- ` - remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列
) W' h! E5 \, ^/ f2 W - set_current_state(TASK_RUNNING);//设置当前进程为运行状态
; V5 Y3 y! P' m5 F - return ret;
- f# Z! x6 z$ |2 \; U& Z( i. h - }
/ G9 D" k% i8 r a2 ?; f
" x! u9 y2 Z* M$ N! A/ F0 I# O. @
# u7 \+ F1 @# i" Q0 c- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)
9 l1 P5 t* I; u* A$ s - {
& s& p" N3 i2 ~6 ~) l - return 0;
- g+ F4 Q3 Z; h; e5 | f5 [2 C - }1 _6 P2 u0 L$ a/ P! @
- /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行; e3 A" y& l0 e- H$ ~+ o/ w& l
- open()、release()、ioctl()协同调用时被调用*/! ^7 f: C8 [. C( V3 h1 g. K
- static const struct file_operations protocol_fops =( W( q& |) p" |. B( T% U
- {& X+ f% s( @7 @3 F
- .owner = THIS_MODULE,
: o% k7 j/ w3 N9 ^. y+ k - .open = protocol_open,
5 R' H& B$ e: D& R3 V - .release = protocol_release,
' ^4 P# y" r! r3 p. x! x - .read = protocol_read,
9 l& ^; B. D- `; e+ b - // .write = protocol_write,
) }: w0 w9 r0 w" U5 r' [) @ - .unlocked_ioctl=protocol_ioctl,+ Y8 z+ S+ Z: P2 I0 k
- };. S1 f! P2 H9 l
2 l4 J/ ]6 ?8 o* k; v- /*设备驱动模块加载函数*/5 L5 |! @& t: o. x9 Y
- int __init protocol_init(void)
0 {& R" I5 r5 s! ~ - {7 _$ o3 i2 y* ~* l0 x. M1 p
- int ret = 0;9 g ~, r6 s, g- A5 F/ b
- int result = 0;5 `% L+ k' [1 ` |# K
- //申请注册设备号(动态)* O$ H& c0 n6 _/ l
- ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); : k4 g9 ]6 {. K. t7 V' S5 H
- if(ret < 0)
7 v8 c" y+ L* z; L9 {) K - {
. t" K* j. }* n5 _5 E( n - printk(KERN_EMERG "alloc_chrdev_region failed\n");
- v0 N/ Z0 D& v! N* h - return 0;" W0 s% ?' c; ~. I: e: D
- }
2 K; n8 m O f: t! j - //分配cdev
* v# S8 F X' }' Q: Q: ?0 u - protocol_cdev = cdev_alloc();9 e" ^6 Z6 M p5 l+ G' S* ]
- if(protocol_cdev == NULL)
* y+ p% p. @+ \% C" R4 W - {4 X" n; I/ Z4 H& {; g
- printk(KERN_EMERG "Cannot alloc cdev\n");
: d1 o* D$ h" P - return 0;
; }: M1 p. Z- x - }
5 g4 o+ E0 D& ^; L( z7 a" k - //初始化cdev
1 j- H" ^3 U' y V# U6 S: U* z/ ^0 Y - cdev_init(protocol_cdev,&protocol_fops);$ d! P j% l6 B& B9 ?
- protocol_cdev->owner=THIS_MODULE;* v( G: I" Q/ {: ^0 `7 M) H% E
- //注册cdev
& W5 p/ B7 \! k7 q3 h$ l - cdev_add(protocol_cdev, protocol_dev_no, 1); ' G, G( ?1 `; K, N- x3 @: r9 B. |- p
- //创建一个类
9 S% E) K6 f% u+ I* k. L - protocol_class = class_create(THIS_MODULE, DEVICE_NAME);$ a: J* \0 r7 w2 T+ N1 T, Z6 B
- //创建设备节点5 q$ ~' R/ I+ M0 b" R$ z O% `4 J
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);/ G+ n( z4 ]0 A" n) N
- 4 o5 h' D4 c# R$ z
- # k$ s- [3 [# j; ~5 x; s5 G
- //申请链式循环队列作为缓冲区DSP数据帧的缓冲区
& G" l) a$ R2 N3 [) m - k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区 F! Z* f" y8 Y; J
- : W7 S# f/ f+ Y3 K8 h: G
- //映射ARM的核间通讯寄存器
- U }- |: @4 }( J* e g - R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
3 Q) O: ~" }0 V - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);# C3 @% N; k. e! w
- //将物理地址映射到内核空间
+ R! f: W" |/ Y1 l5 Z6 L - mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);
. q) D' D3 J' B. l4 l; S - //共享内存初始化/ U4 d; G# H" R
- SHM_ARM_Init((unsigned char *)mem_base);: b) ?8 |# Z [' Q S8 F) G) s. Q
- /*申请中断*/
0 [1 g( P; l& e1 V0 N# G
, x$ }/ @% F1 Y6 l3 P. r- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);+ d; t `3 R( {
- if(result != 0)& `4 B: \4 A9 Z7 ]; k. Q7 t) c
- {3 R- J# U4 T L+ I: v
- if(result == -EINVAL)
, J5 J& }5 n$ {. r0 O2 t; r3 m# A4 T - {
" |6 v' Q9 _7 M - printk(KERN_ALERT "irq request err:-EINVAL\n");" M) {) A0 V& _- k' r& V8 i
- }7 f4 a+ E2 Y2 R7 s
- else if(result == -EBUSY)+ g! d! G* V' P, _6 f8 m0 ~. e4 U
- {
4 |# A2 K* ]' v8 V - printk(KERN_ALERT "irq request err:--EBUSY\n");+ W: Z0 T, D7 e* E
- }
6 j* w1 F$ S$ R \2 M - else% E9 F9 V3 P ^, u& c
- {8 U- e, z; ]1 z& M. ?
- printk(KERN_ALERT "irq request err: unknown\n");
4 n2 V- y' Y5 [; l - }
* W; _! V* W9 X7 F; B - return result;& T0 D9 n( Z0 C' v/ }, F
- }
+ m+ D& C5 x& V1 {. e. h. O - return 0;
& k+ R' ?! i* q+ G6 Q - }' q4 [. g5 ?" O G: K
- ! O/ H$ \% M" {8 @8 X. D1 @
- /*设备驱动模块卸载函数*/
" X o- P# v" D$ _7 { - void __exit protocol_exit(void)& U% L& p1 |' ~9 _* a
- {1 A" s# I3 }% c# w
- /*释放中断*/
1 V; y8 o) K$ p* L - free_irq(IRQ_DA8XX_CHIPINT0, NULL); O$ K$ c2 `: c" ^- H( \
- //释放帧缓冲的内存
x( M! U4 w; [( m* u - k_linkQueue_release(&queue);4 R8 u" s( ^4 ]. Q- E
- //释放寄存器映射) i/ H( P; a$ {$ `# e1 v- j" G
- iounmap(R_CHIPSIG);
) R/ n! f5 P! `2 U/ r - iounmap(R_CHIPSIG_CLR);
- s" s8 ~& d! g7 n1 W/ b* T% r/ C - cdev_del(protocol_cdev); //删除cdev8 V3 W& \4 P5 S4 ?; d
- unregister_chrdev_region(protocol_dev_no, 1); //注销设备号
: B5 N$ i. _4 r8 @- d) g: W2 X' J - device_destroy(protocol_class, protocol_dev_no); //销毁设备节点 F# `; O% S Z! s
- class_destroy(protocol_class); //销毁设备类% ]+ m( H0 [$ R. S2 m
- printk(KERN_ALERT "exit success\n");- r& E) q! Z$ W0 I7 D1 g6 x* R
- . @7 G) M1 o: h4 v1 P
- }
5 b, m- T! ? U4 H - //驱动其他部分省略
复制代码
8 M' z# C" |5 S1 C* @# e6 o4 N/ X h" ^8 s6 ~$ u
|