本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑
/ c4 g) g) Y/ p) t6 V; z5 k2 o/ e0 |. p5 \; v* T$ w. o3 x
项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略
, X1 N6 E" W5 F! W - : S6 J5 Q7 k$ x8 s) j
- //引入其他模块函数和变量; x1 ^. W2 m1 ]; k% ?2 H
- extern Ping_Pong_Buffer res_buff;
( u C, U5 M/ ^& c; w0 c - & b& r3 k' p! E' x9 u. U9 |" l
- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列$ L; c. c D. N$ g
- extern void k_linkQueue_release(linkQueue *queue);//释放链队列/ ]# z( Z d3 Y; K
- extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据4 e0 _. k. {/ E" r
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据$ D" \& s, M- \, L/ l! r$ M
9 W" Z& g8 d$ o9 ^ I$ e- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化! d/ ?5 j/ Q2 S& @! v4 K
- 1 V2 z+ E) l a- s o
- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置1 W, P [/ E3 ^. [% h. B, `
- //设置主从设备号
2 L9 j9 p3 p5 a' L+ {. e$ B - #define PROTOCOL_MAJOR 1+ t4 h+ ~; G3 k
- #define PROTOCOL_MINOR 06 k1 k& C I5 e2 P: v6 w
* O) v5 o9 V0 d+ ?( Q' \
% e$ J$ k$ O* ^, O8 I" w- ) w2 U8 \1 Q* g" w3 |( ^ A3 T
- //定义设备驱动的名字或设备节点的名字+ s4 O9 o' b+ Y- o+ N4 b$ }1 x
- #define DEVICE_NAME "protocol_driver"
( m7 X) p7 t; a: T - : y7 ^7 F$ Z. Y: x9 f
- " _ ` K* e; R; b1 |6 ?6 k7 ]
- //定义全局的循环队列作为数据缓冲区
1 t6 Q2 _6 K: M: D+ j1 d1 Z - k_linkQueue queue;6 w9 i$ P9 c. |6 F; J* _; ]0 G
! O+ S9 P9 B* Y9 n# u- //寄存器地址映射全局变量
" P8 C. E4 W# @. `) C* L - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器
+ L+ I7 l- |8 z$ D* @ - unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器
0 x6 l, C& W+ }2 p. H X3 k, e - $ Z- X; {- l* d
- //物理内存映射全局变量+ n. ?3 P6 c2 p% E' r; c' E
- volatile void *mem_base = NULL;& A/ w; l4 H( @
- volatile unsigned char *cur_buf_ptr = NULL;; A/ ]; h* t) `& c6 [" }9 z4 I# `
- volatile unsigned char *data_ready_ptr = NULL;
7 @/ O+ p" L, Q2 Q2 r' E3 a# E1 O/ h( v
: e9 C2 h. E5 m- ' Y( H) Z, Q# d0 ~/ ~7 P7 J
- % y' b: F7 s) M$ x4 A. R
- //定义读数据等待队列头,IO阻塞! i% M. Y& g+ _8 F5 C2 r& ]
- DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);, w( v- H! S% G M& j2 g
- 1 \! H9 G3 c4 R; P
- //定义原子变量
( E% A X! C! a - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备
' Z. M# W$ ]6 Y5 C
. p6 N4 {1 b, L6 l2 o! W- C& }+ q& |9 v- u H
- //定义设备类* P7 i% _# R7 D" N f
- static struct class *protocol_class;
' j @& o! r0 M+ ], b; N& \ - struct cdev *protocol_cdev;
) z" p8 s( ? c - dev_t protocol_dev_no;
5 q" Q+ T$ P$ J; \* N# R - 4 K0 C' A) ?9 ~$ r$ ^8 @
- /*定义tasklet和声明底半部函数并关联*/
0 g# _) w9 e: D6 I* ] - void read_data_tasklet(unsigned long);
. X: p( U/ l1 C1 n0 D - 5 U8 r3 b. G* j6 a0 D
- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);8 Z5 H0 [6 B4 U1 ^! ?+ s( ~
- //将CHIPINT0_tasklet与read_data绑定,传入参数0# K4 I. E1 C3 N; {. \
5 e2 q& q/ J. s! U7 P. Y8 g; H- /*中断处理底半部, 拷贝内存*/0 X2 }6 F: ]8 e0 M
- void read_data(unsigned long a)6 `8 S' i* a$ u5 e0 G9 B
- {8 B7 S, B& H9 U" t. E( Z
- if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为1
+ L$ M- c$ J2 O9 K - {
- s( g6 K. i, e" P" {: C7 T - read_quest = 0;
/ ]& K ~/ B Y0 ]" i - wake_up_interruptible(&wait_queue_head);//唤醒读等待队列5 m. m3 U2 @% z& U: N
- }
5 p; C* a1 N- w; \# w
4 g* W: y5 J; E1 u7 P" W; z- w5 w- }1 Y2 ^1 q& n2 q! f0 A
& T6 A3 X9 q9 z" Y2 s- K- /*中断处理顶半部*/0 i3 t; r; b8 s& k) d
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)7 H6 k8 Q6 A% _7 W6 q+ _2 ?
- {2 ~/ @5 e, `, ^/ ^
- //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样( ]. x1 z2 I# j0 f. y
- volatile Buffer_Type *next_read;
9 S' f/ j7 _5 W - //如果DSP数据已经ready. e5 v" E4 |8 D7 L7 E3 w
- if(*(res_buff.cur_buffer->data_ready) == 1)+ A4 i' f3 m0 Z2 p) s
- {6 B* _& O. a4 {
- if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer: G; X% H5 @$ V# w- g) E
- {
" N) t* R) p. p1 e1 f7 ^, L - next_read = &res_buff.pong_buffer;//下一次中断读pong buffer8 \! e' `" U5 l( E2 A
- //printk(KERN_ALERT"read ping\n");3 G4 r% l6 I# p1 S
- }
/ R7 z& v/ W* }( w - else6 E m3 T9 I( m5 _! y7 s
- {
+ r I1 y/ ^: M# U9 b# A. Y - next_read = &res_buff.ping_buffer;//下一次中断读ping buffer& J8 a* D6 y ?
- //printk(KERN_ALERT"read pong\n");
4 r5 G1 T# P, Y$ c. j - }
* P4 y4 Y- X6 ?( ], }4 Z0 \8 |0 f# U - *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer9 @( ^6 ^' W( V
- //将数据插入链队列% k/ e1 u! m, q; T
- k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);
# E u' N, O% F6 _9 P' ~, ~; [/ v - //标识位都重置; { p( o: f" j$ [
- *(res_buff.cur_buffer->data_ready) = 0;
. |3 S* Z6 X4 j. O, H - *(res_buff.cur_buffer->data_size) = 0;' P; k4 b1 [& M O) P( \
- res_buff.cur_buffer = next_read;
0 s* t) M! S; U" J - }; U) N. p8 ^. n7 t. d9 u0 F! P6 M. r1 |
- //清楚中断标识" c& f' t1 _9 N
- *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status
/ Y k8 c# `( l# v - tasklet_schedule(&CHIPINT0_tasklet);//调度底半部
+ c7 B5 l9 X+ z" U& O7 r$ u' y
( m; w) v$ i5 m/ h3 h! ^4 z- ) B7 ~4 A/ j8 `; w* k5 J# w
- return IRQ_HANDLED;
0 B: ]( l4 v9 R9 H8 b' K - + D4 g/ M; a. C) N
- }
8 [* y) S) ?0 ?" \
' c4 r/ s7 I# B5 B/ X) X. y- //文件打开函数% w7 N0 _2 s; X( n$ M2 \5 R
- static int protocol_open(struct inode *inode, struct file *file)1 ~( `; n; w5 a. {% I" ~; ?
- {
. S- M5 d! M2 b% ~4 }& S& V - int result = 0;7 q7 {% n& e r$ [! l, N
- if(!atomic_dec_and_test(&dev_available))
! N" M3 y) K' v, r! c - {
; |' a3 n$ |9 i" t9 C" z/ @; i. c - atomic_inc(&dev_available);+ I. ?( }8 E2 B. U2 F
- return -EBUSY;//设备已经被打开
9 i9 ~) _9 Q% F0 G3 B) G - }2 d" m3 s( g/ S q% r3 \: n
- printk (KERN_ALERT "\nprotrol driver open\n");
" {5 d8 i9 ~' y) T4 T3 H/ U1 X - return 0;
+ W" U M9 K D - }
8 _/ x4 @" t; u9 G5 \
+ ]8 T Y5 ~1 A% {3 k- //文件释放函数
" P- M, ^ u3 s. ^ - static int protocol_release(struct inode *inode, struct file *filp)- W, X4 |1 ]; ]
- {+ a: K' ~+ m b% ]. z) g
- atomic_inc(&dev_available);//释放设备,原子变量加1% v9 C4 |# Q$ S1 J6 [
- printk (KERN_ALERT "device released\n");9 y8 `: Q5 K7 m7 N7 C1 t8 s
- return 0;
5 f' j4 I, {! T- h0 U0 s - }
) M. Z3 C% ?0 L - ; i0 V9 _6 Q, _
- //文件读函数
+ B T6 i( l+ L7 J! { - static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)9 [/ q% g W5 r$ W8 ^$ [1 B
- {
" f" j$ g k1 P9 V2 Q w8 T/ h4 | - int ret = 0;
- x* a! S( n5 |* x! e5 S - //定义等待队列
9 \" d9 h# |9 }% G1 Z8 a# e - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列# `: r, G$ x4 ~$ h9 \. p
- add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
# p5 n4 J) r8 J$ n. v9 n( Y7 a - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据3 l8 {! O/ N# A6 c) p
- {
# f0 X0 l' C8 T) C8 T; W, e/ r - //printk(KERN_ALERT"\nbuffer no data\n");6 \4 B8 O; S# s% A1 y, q
- //如果是非阻塞方式读取,则直接跳出6 J: X5 E" @, i: h4 I$ Q% o$ f
- if(filp->f_flags & O_NONBLOCK)2 i1 r4 a9 k1 N% z% X! }/ o J, E
- {
9 m- V' W8 z/ b! |; I; ? - ret = -EAGAIN;
6 Y: a0 b/ S( e. S! P' U# R - goto out;0 y6 ~' ~+ T* }' A5 c L+ S' u9 l
- }& h/ M6 Z- r8 S" B* b3 x
- //阻塞当前进程,放弃cpu资源* f/ j, S1 _2 a" z6 w9 h" H
- read_quest = 1;; ]' M% O* ]0 v* p6 A. i, o2 }
- __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠
/ Z5 t; z; a- l, j3 V' V - schedule();//调度其他进程运行 x# H( y1 R9 ]
- if(signal_pending(current))
# ]" h+ Q& B/ v; b - {
8 u7 D8 u: W/ E9 }+ Z* a8 s! z+ V - //如果是因为信号被唤醒,则返回到系统调用之前的地方
3 Z3 T4 c/ ~' Y; E+ E% c! H - ret = -ERESTARTSYS;: i& {2 Z; V5 j
- goto out;
6 P2 \* k- J7 Z - }
- m( V. {: _, K/ _/ E7 s- o - }
5 x1 j; ^8 u. r - //将数据拷贝到用户空间$ ?" [6 q! ]) b. [+ X
- ret = k_linkQueue_getData(&queue, dst);
% B' {8 D) X! R' C - if(ret == 0)
3 l/ L, Z) v% k. @ - {9 x& o) v0 \, E
- //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);2 C7 |0 b8 y6 z' L
- }* q! m1 r3 E; X
- out:
: o, M7 U4 V3 b' W- m6 \# J - remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列; C4 b( t4 f0 `* |* j
- set_current_state(TASK_RUNNING);//设置当前进程为运行状态
% W4 H) ~0 |& j, r9 o! ? - return ret;
2 ]0 b$ d& `3 b8 a6 n: S - }( F: E% Z! R7 ^" K- x5 A! r
9 Q* {* x9 H, c+ u9 m, E$ E0 C9 F
, F5 C, V5 N" ?* r- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)5 q) d2 A4 ~2 T
- {/ B0 W: B3 z$ `! F. Q
- return 0;0 U8 |! A2 ?! W# J5 V% ~% W
- }
7 B- Q7 |7 V& J) l: o - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行
- H9 c$ Q7 N( H( E1 {' A1 C5 i9 ] - open()、release()、ioctl()协同调用时被调用*/
( P5 Q- l$ L: s: C3 Q - static const struct file_operations protocol_fops =
2 r7 Y6 V, t" p; K- \ - {
8 d3 e8 e5 D7 ~/ O - .owner = THIS_MODULE,( V' z7 A2 A4 P1 W& Q3 q5 K, O
- .open = protocol_open,
' E7 z6 W1 Z5 ] - .release = protocol_release,9 g( E6 H. A! E a0 e) ~! k- Q3 O2 ]$ Y
- .read = protocol_read,* Y' R0 N- q+ @
- // .write = protocol_write,
. V% f( N/ x: W1 y9 k - .unlocked_ioctl=protocol_ioctl,
3 o2 _- H0 B6 t - };
8 D+ W( t: W/ F1 ?3 E
2 |! y- C4 U6 D- /*设备驱动模块加载函数*/
9 w7 b# l; [: P3 C - int __init protocol_init(void)% _- S3 q, Y8 e6 A) y3 ^) A- r# \' I* @
- {- C7 n5 v( ]& e4 [4 G' m4 `
- int ret = 0;' R+ k/ i" X- Q
- int result = 0;
% D4 U3 p9 j3 X) o- d - //申请注册设备号(动态)
* f8 v5 \4 J* g( p - ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); 4 X6 Q' e$ Y: x G
- if(ret < 0), j+ R+ q) \" N$ f, u8 N0 b) E) P$ X6 {
- {
" t6 f/ p' l* r/ L J: D - printk(KERN_EMERG "alloc_chrdev_region failed\n");/ b$ Y: J4 M9 t" s2 [4 f9 j
- return 0;
5 E2 R" s/ o: i E# Z, u - }, U/ a$ e2 k+ V; W* g
- //分配cdev
* W# |3 |+ I# O/ B - protocol_cdev = cdev_alloc();: U/ @7 u2 j4 b/ y
- if(protocol_cdev == NULL)( K7 E3 I- y4 v7 O3 V2 B
- {
4 j8 G) e) W# E4 O - printk(KERN_EMERG "Cannot alloc cdev\n");- Q9 s% e* U) P/ u1 ]
- return 0;( M5 R) T9 B) T9 q* V1 T6 h
- }% W% S, F5 B' K' n. N
- //初始化cdev; }5 y7 ~1 X( f9 Z. T9 m/ g& V
- cdev_init(protocol_cdev,&protocol_fops);# d* y) O1 o l. i8 x# {0 }: ?
- protocol_cdev->owner=THIS_MODULE;% G. `8 |* v$ T: }
- //注册cdev
! y- ?* B+ J- a, V$ t$ H6 ? - cdev_add(protocol_cdev, protocol_dev_no, 1);
9 W, V) L8 g) `6 @ - //创建一个类
2 X( y7 \1 K% L - protocol_class = class_create(THIS_MODULE, DEVICE_NAME);0 l( e" w% `2 f5 [3 q
- //创建设备节点
& J8 ]: i7 Q/ m, E* I. E4 P - device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);
% o! y. A* _: p% [$ c -
- ?4 B$ \0 A6 r# J( M -
/ s4 K' }+ u+ }! K" A - //申请链式循环队列作为缓冲区DSP数据帧的缓冲区' p/ y6 u9 k1 o7 E
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区6 P4 L+ K6 n& \ w3 v/ h, P( t
- : }. L- A0 @* y
- //映射ARM的核间通讯寄存器
) L" z0 S/ e- O) H/ F6 a - R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);
6 `7 v/ n7 {) }) T* [+ w# \ - R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);9 |8 p5 D7 @4 n# l% |
- //将物理地址映射到内核空间
% l: F+ s+ {( ]% h4 C d/ q - mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);. c5 p" q, F' G" M) ]
- //共享内存初始化+ z8 U. W9 G+ s3 J# Y& W
- SHM_ARM_Init((unsigned char *)mem_base);
% G' ]9 r4 `. Z d1 V- k7 V# D' I8 L - /*申请中断*/
2 q" f, N( I8 G - : G3 n& @1 k+ Q' j6 q2 s* W6 b
- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);
9 ]0 v2 A8 r4 |4 B( D4 @4 T% j+ S - if(result != 0)
9 j4 Q1 u% M9 n2 q - {
7 f5 U6 ]! t, d: u N' ]3 u1 d' Z% W - if(result == -EINVAL)5 W/ H5 v$ \1 n
- {
" M% q+ n* A% L( y/ d+ `% a; ^ - printk(KERN_ALERT "irq request err:-EINVAL\n");
8 N. S6 I8 P, R5 {) u$ ~/ u - }
5 b, o" a" T; p2 T6 r+ v - else if(result == -EBUSY)$ A% U5 o, y7 w& E; ~
- {
- W4 g$ J- p( V. t8 t0 T+ b; J8 B - printk(KERN_ALERT "irq request err:--EBUSY\n");: J# e7 M5 \9 P
- }
& ^9 {. P/ O/ L - else
. u: ~6 j# X8 @ - {
# o0 X1 c. h/ \3 Q/ I7 B - printk(KERN_ALERT "irq request err: unknown\n");
" v0 @$ m; }0 @0 E* ~8 l - }
% r2 O( l; G* E* Y/ z - return result;
8 b- y; U) s* n5 M& a. y$ D. i - }/ u: U$ J, A, h" D) I
- return 0;3 j" e7 ^- M4 A) e, U7 A
- }& z, L+ o; R' f# L2 q. [; _
- 4 n5 n# r. A" Z) T9 V0 c
- /*设备驱动模块卸载函数*/
% ?( `) L) D5 x6 Q& S9 u7 g: p - void __exit protocol_exit(void)
9 [! |. t: R4 V$ A8 ]: [4 x - {
! ]8 o( F- h6 f' U: @4 e - /*释放中断*/
8 _# s6 ?( I. ` - free_irq(IRQ_DA8XX_CHIPINT0, NULL);, i0 h) p5 Q2 {) f2 e" V- f
- //释放帧缓冲的内存3 s S0 d9 j. O Y
- k_linkQueue_release(&queue);. X1 ^8 G! \2 m" K0 r7 W
- //释放寄存器映射
0 a$ A" w$ O( C, j" j - iounmap(R_CHIPSIG);* {* W& W6 `9 u" G$ ?; _7 \
- iounmap(R_CHIPSIG_CLR);8 P, [2 H7 v N
- cdev_del(protocol_cdev); //删除cdev
& E; o- c! _" N* w - unregister_chrdev_region(protocol_dev_no, 1); //注销设备号9 A* ]: i- e I# \# ~( [: G
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点" `% v7 g0 v: s z0 I
- class_destroy(protocol_class); //销毁设备类+ x4 _; j; g( V% Z& ^* [, d4 w: _5 K4 \
- printk(KERN_ALERT "exit success\n");' v9 W% t- \3 M: K, w
- 2 o) `1 z& \1 Y4 v8 y, _# ~
- }
7 i& D1 d8 D4 ~2 z* ` - //驱动其他部分省略
复制代码
3 f, C: \# E Q$ [' S8 e* ~; U6 |5 c l- P X* u
|