本帖最后由 wwfdzh2012 于 2017-4-17 12:09 编辑 $ M5 [7 l1 z1 J4 g4 {4 A7 {
( z. P9 F7 g9 K% L8 z4 k项目要求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核会响应两次,也就是顶半部会触发两次调用!!我的驱动实现如下,麻烦帮忙看下。 - //头文件省略0 S3 v3 w2 {( U& E- t
- 7 Q3 r1 M4 V% J, Y4 \* r( f
- //引入其他模块函数和变量8 j+ F: ?( ~) [6 t2 Q8 H4 C
- extern Ping_Pong_Buffer res_buff;
7 e' {) S) X6 e- O) B$ Q. j$ j - / D# Z8 }8 }; y2 Z+ W
- extern char k_linkQueue_create(linkQueue *queue, unsigned int dataType, unsigned int blockNumber, unsigned int blockSize);//创建链队列
: U0 a- g( \/ s- D - extern void k_linkQueue_release(linkQueue *queue);//释放链队列- C" ^( H" x' d- A5 r! Q" x
- extern unsigned int k_linkQueue_insertData(linkQueue *queue, void *data, int force);//链队列插入数据* \1 u! ^* c% Q5 n
- extern unsigned int k_linkQueue_getData(linkQueue *queue, void *r_buff);//获取队列的数据+ a( V7 L5 F* s" t/ @
- 5 i* G4 @7 H1 K+ \2 }/ J8 R
- extern void SHM_ARM_Init(unsigned char* const mem_base);//共享内存初始化% C" j; X$ n/ Q7 y' z
- 7 {7 I1 k0 S8 ^1 n- k6 Z. Z" A6 B
- static int read_quest = 0;//如果有读取数据请求且链队列无数据可读,则置10 J1 f n: [9 {
- //设置主从设备号/ s" S9 G! b \) i$ M- ?1 I
- #define PROTOCOL_MAJOR 1
! ~, B2 v4 a+ l; m: Q( K: m0 d - #define PROTOCOL_MINOR 09 H; s* T% o/ v( D- K1 k% s- p5 N; w
2 w" J" t( s% Z0 [1 y- 7 N' b2 r6 n. I b
- 5 f- `- a8 G& d" Y k2 P' B) k
- //定义设备驱动的名字或设备节点的名字: }; q' l& W; j [) L5 ~0 h7 }
- #define DEVICE_NAME "protocol_driver"/ }! S0 O& K( C
) k' @3 j% q) H6 f# U
6 C# S* [: k$ N+ @- //定义全局的循环队列作为数据缓冲区" Z- _+ N& q/ u$ `# O7 \) ^
- k_linkQueue queue;
. m4 z% D/ X; m# Y, C3 E( n/ l7 k - * }; s% g1 l1 S2 M8 b
- //寄存器地址映射全局变量
5 [8 T, n% a5 z4 R* C( E - unsigned int *R_CHIPSIG = NULL;//CHIPSIG寄存器
7 H$ `4 Y, _) m+ P. Y - unsigned int *R_CHIPSIG_CLR = NULL;//CHIPSIG_CLR寄存器. |) ^ q+ {8 M; L8 k+ n8 b
- / c( b+ |% @1 \7 D. b
- //物理内存映射全局变量
; n8 I7 s! M/ Z$ S0 B - volatile void *mem_base = NULL;
( u9 ~$ p5 n" Q" c( J. L* x - volatile unsigned char *cur_buf_ptr = NULL;! C0 f j7 X2 m6 m: L
- volatile unsigned char *data_ready_ptr = NULL;
% V: w2 U* a5 }" D
2 b+ E0 k$ S H; ~- 9 H! m( ?% M8 K4 e3 C
7 b2 n9 _/ B3 W4 ], h0 P- //定义读数据等待队列头,IO阻塞
0 E* u9 C8 ?# r j5 w( S" N4 |$ h9 h - DECLARE_WAIT_QUEUE_HEAD(wait_queue_head);
* T) d6 U# P; L, F - 5 W+ `% j: m* _; U& v' D4 A
- //定义原子变量
' F. O' ? w2 `6 u0 ] - static atomic_t dev_available = ATOMIC_INIT(1);//原子变量的值为1,即只能一个进程打开此设备
2 E+ v% t D6 b, y9 t0 A - + [# v6 l ~. E( ?' l [3 \- B7 O
- 5 }8 B5 Z# [4 H# |* h
- //定义设备类. t J% c u+ G( z
- static struct class *protocol_class;
/ S1 W" i/ @' n- j( l/ z - struct cdev *protocol_cdev;" C) u' d( X, D4 ] `8 c
- dev_t protocol_dev_no;
$ y j4 C# e R9 f$ {3 ~ - 4 ^0 G' J+ M# b, v2 ?* _
- /*定义tasklet和声明底半部函数并关联*/
# f+ ~9 T# J) p, k z( T! ^ - void read_data_tasklet(unsigned long);- T7 d7 Z* ^; L; [* N
- m( m: v6 t+ |$ h0 m5 t- DECLARE_TASKLET(CHIPINT0_tasklet,read_data,0);
& I5 |: s$ s5 T, L6 ` - //将CHIPINT0_tasklet与read_data绑定,传入参数0+ q G' t4 c' q. _& |: J
5 W! E* ~/ c( o8 L5 E6 w& i2 z- /*中断处理底半部, 拷贝内存*/
1 s \/ ~8 D4 }2 t: k1 T- H) { - void read_data(unsigned long a)' |5 H8 F# e- f4 v
- {
" `5 W9 o2 w8 \7 G4 e - if(read_quest == 1)//如果进程调用了此驱动的read函数且链队列没有数据可读,read_quest将会被赋值为15 x$ G! i. u, E3 C2 n/ H
- {
: w! ]6 c# M) K- E( Z; m - read_quest = 0;7 C& L; w& E; ~1 K6 ~2 @) a0 _0 K
- wake_up_interruptible(&wait_queue_head);//唤醒读等待队列
) m( j$ |# H' B - }( f y9 d- K8 X, r, N# C
7 D% x: d' \; @5 `% J$ S- }
3 b, r. Y6 R; A2 [: q4 O3 L1 ? - 6 w- ^# ?( h+ _3 P& a/ c |9 Z
- /*中断处理顶半部*/- V* F4 u* Q# ^! H% y
- irqreturn_t CHIPINT0_interrupt(int irq,void *dev_id)
% i. R# t( r4 G& [5 ? - {
C8 } g" d, [, f - //只要一触发进入这个程序,其他驱动会出问题,即使这个程序什么都不做也会这样" Z9 t2 O% f! b4 Y6 e% ?
- volatile Buffer_Type *next_read;
' j. \1 i, `# Y/ L3 x6 s - //如果DSP数据已经ready2 ~9 W' s+ g% z
- if(*(res_buff.cur_buffer->data_ready) == 1)
) Y9 u1 l8 v" B+ O9 Q M0 d; R - {
5 d( w' ~2 O" q' ^0 |! {5 [ - if(*(res_buff.bufferID_ptr) == BUFF_ID_PING)//切换读buffer
5 m# G, k9 R$ r6 ~ - {7 }" `! J9 w& h, I% Q
- next_read = &res_buff.pong_buffer;//下一次中断读pong buffer
2 M/ ^' D' R8 W - //printk(KERN_ALERT"read ping\n");
3 s% S+ G+ y7 H/ e - }0 `3 |9 |# b9 N9 i' Y! z
- else
+ ]' T x- J: w! J - {$ ?5 H2 _/ J7 S v
- next_read = &res_buff.ping_buffer;//下一次中断读ping buffer
8 Y+ w6 C q7 _1 M5 j% U - //printk(KERN_ALERT"read pong\n");
: _ p5 j1 S% s. }" v: u - }
0 B5 D/ H3 ^# G. q - *(res_buff.bufferID_ptr) ^= BUFF_ID_PING;//切换DSP写另一个buffer
; R3 I! w. m$ s6 j2 a1 u - //将数据插入链队列$ N: F9 E0 q5 R* j
- k_linkQueue_insertData(&queue, res_buff.cur_buffer->buf_ptr, 0);/ T, }- s# L2 j- E, ?
- //标识位都重置
$ a9 R1 d$ H Q8 X5 U - *(res_buff.cur_buffer->data_ready) = 0;
; T: m; @9 G% f- ^2 o - *(res_buff.cur_buffer->data_size) = 0;
. o& V4 b; ?3 U' P - res_buff.cur_buffer = next_read;& t& T! U3 C( @1 i7 |2 v
- }- |( k) v2 [, Z }8 W* o
- //清楚中断标识
* a9 Q. \* p4 y* G5 R8 T - *R_CHIPSIG_CLR = 1 << 0;//clear chipint0 status0 g% m! t6 v5 M1 A& w
- tasklet_schedule(&CHIPINT0_tasklet);//调度底半部 % q8 S# g0 [' g1 ]1 `8 M" K
" \0 @- I4 |3 N; V$ e- + `) V; m/ V: l
- return IRQ_HANDLED;6 [2 i q5 d. F+ U0 f$ ?
- 8 F( a" y9 k2 w4 w/ |
- }$ K- o" x8 V$ @; D
- 4 D* p- _5 T; }2 X. {4 } t
- //文件打开函数
. m' v; K0 D4 a" D - static int protocol_open(struct inode *inode, struct file *file)
" Q6 U6 g8 m. i6 `$ B - {2 g+ l3 K0 ]' A: \
- int result = 0; T9 [/ g/ r N
- if(!atomic_dec_and_test(&dev_available))
, J! E$ L9 w3 P* b" K$ N - {
% W( ~5 s* l0 C$ Z/ M5 n - atomic_inc(&dev_available);
7 T5 [7 M) Q4 P3 a/ G4 ]# f - return -EBUSY;//设备已经被打开
3 x) ?) E/ I/ F" _' | - }& N( R% o' s3 C4 g* C
- printk (KERN_ALERT "\nprotrol driver open\n");
- @# p2 A! P9 s. g( c: O5 ^ - return 0;4 j1 e: ]3 I" p) ]( t
- }
, C% w6 Y+ F' \6 h( O. s
) S" K4 g! w, P* z% z- //文件释放函数/ c* p; A4 r) d* e4 W/ i a
- static int protocol_release(struct inode *inode, struct file *filp)# g) c0 U2 _8 V* E# X# R% q
- {
: ?8 G: f3 o$ j# k - atomic_inc(&dev_available);//释放设备,原子变量加15 s5 ]: m5 f$ C9 a5 V& r; w: Q, A9 ~
- printk (KERN_ALERT "device released\n");
% L& e# ^& D6 ]4 W! g+ H* p( H - return 0;5 {7 N+ T. e6 ~ R' w+ e
- }
- C' ?2 x M9 C: E - 6 D5 o* y- u' [: R
- //文件读函数
$ Y1 w. ~0 }- x, v- `% I n9 G; J* ^: D - static int protocol_read(struct file *filp, char *dst, size_t size, loff_t*offset)) [1 S" k! }- d0 G% d) H
- {
$ ]$ V2 u! t. I" L - int ret = 0;; _& h2 o- D4 M7 M# |- M
- //定义等待队列
( ^6 e, {1 `" f! T( ^ - DECLARE_WAITQUEUE(wait_queue, current);//定义等待队列
8 h) s3 ]5 i) y9 c0 A" } - add_wait_queue(&wait_queue_head, &wait_queue);//添加等待队列
1 X" t1 x0 s$ q( | - if(queue.remainNumber == queue.blockNumber)//当前buffer没数据0 e& ^) _) R! z1 `
- {" z) F0 A; j% E" v8 x
- //printk(KERN_ALERT"\nbuffer no data\n");" P& ?5 h$ v( \7 ?4 Y
- //如果是非阻塞方式读取,则直接跳出/ Q8 ~1 B0 T r3 W
- if(filp->f_flags & O_NONBLOCK)$ n2 @# y) W4 d6 O9 x6 S
- {) I f. H4 r( M! [
- ret = -EAGAIN;+ @9 h' D0 ?& J) t+ J7 v
- goto out;# J, Z, B0 A% h
- }
. p, x4 S7 |0 q) }" C - //阻塞当前进程,放弃cpu资源3 l7 j+ r) c& d! l6 ?8 p& W x2 I0 K
- read_quest = 1;& G7 ]( f. |" ^/ ~
- __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠: f; n& ?2 p' T I) Z; M2 k
- schedule();//调度其他进程运行 g$ A4 Y( Q& J' o3 Q8 L- ~* ?) d
- if(signal_pending(current))
: R- I; K z/ ] - {
' q, I1 |" v2 G- C# ] - //如果是因为信号被唤醒,则返回到系统调用之前的地方
8 h. u/ [' ?4 ?8 E - ret = -ERESTARTSYS;
" x7 v8 ?8 s* X) ~: j& I+ C - goto out;
7 s! n7 `, R# R1 L7 I - }
! G+ ]9 b5 Z* j9 S - }0 X1 V8 R- \- s. e; E
- //将数据拷贝到用户空间( f; D, L' _8 ?2 D/ }, }( \
- ret = k_linkQueue_getData(&queue, dst);/ ^4 n7 F+ g ~/ d/ k6 X
- if(ret == 0)
4 B4 J8 v4 G- }* D7 I - {
5 Y7 ^# ^. g% S2 U - //printk(KERN_ALERT"\ncopy data to user space failed :%d\n", ret);
* @5 ]5 e9 Z" F4 p+ S4 Z/ N$ w - }6 w' T0 H7 _& ^: a4 G1 k1 F
- out:
5 J1 Y: y x, |( F) } - remove_wait_queue(&wait_queue_head, &wait_queue);//移除等待队列
) b( [& F" x3 t - set_current_state(TASK_RUNNING);//设置当前进程为运行状态
c) l% c( `0 [0 [/ S - return ret;
# ]$ v& [. ~( B - }
1 l' ?/ c0 l' K4 b7 o
1 Q. n+ z0 }% p& R4 F
+ {( z. D" n) R0 R- z) U' ]. L. ^- static long protocol_ioctl(struct file *file, unsigned int cmd, unsigned long value)
. D' x' z- B- G' F: \ - {
7 `: o1 s2 C& ]6 ?0 U* z0 ] - return 0;
0 C# G$ Q8 Y A - }
: q; g q' ^& p) c& `4 \ j& z - /*驱动文件操作结构体,file_operations结构体中的成员函数会在应用程序进行
; w& ^1 j: O+ Q5 \ - open()、release()、ioctl()协同调用时被调用*/
A A0 B4 J# [( N Z - static const struct file_operations protocol_fops =0 V' w. {0 N* t$ k( E
- {
9 F& P6 p& Z; N; S: Y* b - .owner = THIS_MODULE,
* w+ l* h9 U" G( P' g; R* z) G+ L% k8 p# {$ B - .open = protocol_open,0 ^4 S, R% J0 ^. h0 G
- .release = protocol_release,
3 ~3 Z& e# l/ j( u - .read = protocol_read,: i- u2 r! p2 H$ k% T% k2 t0 ^
- // .write = protocol_write,0 D4 N4 n4 b0 n; l
- .unlocked_ioctl=protocol_ioctl, b& b- A! }3 k3 m5 m' q& Y2 w
- };
" A2 V% ]& \0 b& B - % \8 J0 a. X7 X s1 O' P$ p8 ^9 _
- /*设备驱动模块加载函数*/; T! m1 Z& F% A; F. c
- int __init protocol_init(void)
) A) R" v) L$ M: P- k4 E! a" P - {1 d/ A9 D K" \
- int ret = 0;
" e6 L# Y. l( A - int result = 0;
+ Q& [" r: f* P. q: Q; _ - //申请注册设备号(动态)' g7 t! {6 R+ E; m' ?# V& D
- ret=alloc_chrdev_region(&protocol_dev_no, PROTOCOL_MINOR, 1, DEVICE_NAME); + \: \! I* N. O Q6 ], k4 Z
- if(ret < 0); C; J# ?* E8 B. A0 T
- {
- o1 q e- e' x8 q J6 Y, Q - printk(KERN_EMERG "alloc_chrdev_region failed\n");3 s* v# j6 L% `& {
- return 0;+ u u$ t$ g, s I: M4 m1 ~ K
- }
; A5 C& m+ v7 @: R - //分配cdev
d: A0 X& e, A! R - protocol_cdev = cdev_alloc();5 w% R* \! s/ Q$ U
- if(protocol_cdev == NULL)
7 \) v8 t" d7 r1 |7 D - {$ P1 }& H$ t4 u; G' G, i9 z# s- {0 r. ?
- printk(KERN_EMERG "Cannot alloc cdev\n");
2 ?+ }- c. r7 I - return 0;
2 h1 d& ^7 ^2 @& W, S# `" o - }
& A- E! {8 ?* b( Y6 ^: y: S - //初始化cdev
$ w) N$ L9 T! r/ w+ t" p2 A - cdev_init(protocol_cdev,&protocol_fops);
* \. g7 Z0 X. W- {) h: L - protocol_cdev->owner=THIS_MODULE;
) j3 V$ `# ~7 d M/ S$ H H' [7 j - //注册cdev
i" Z. `8 e1 x- B/ S2 R7 k - cdev_add(protocol_cdev, protocol_dev_no, 1);
1 F7 z% x- }$ N) f7 y. d - //创建一个类
G, ~' N7 r: B; o; ^ - protocol_class = class_create(THIS_MODULE, DEVICE_NAME);0 a; s( t& |% Z' _5 e3 }. g
- //创建设备节点' E4 P* b. K- c, y- J( Z6 V2 x
- device_create(protocol_class, NULL, protocol_dev_no, NULL, DEVICE_NAME);
8 e- X) b2 o, i T S - 5 Y9 p7 n( g9 K
-
4 F1 z& ^" ~5 ] - //申请链式循环队列作为缓冲区DSP数据帧的缓冲区6 i1 S/ D! K8 g" I
- k_linkQueue_create(&queue, sizeof(double), 1000, DATA_BLOCK_SIZE);//申请1000个blocksize的队列空间作为帧缓冲区; o E& b2 Y! H5 x- P: e
- ( _2 A. q' u1 X: J" w# D) d; x
- //映射ARM的核间通讯寄存器0 O: h: |0 z' l9 D
- R_CHIPSIG = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG, 4);* A* [( I" V, Y2 Y
- R_CHIPSIG_CLR = ioremap(SOC_SYSCFG_0_REGS + SYSCFG0_CHIPSIG_CLR, 4);
" s* Z% e6 c! |3 k - //将物理地址映射到内核空间
( b0 V& P7 e) |6 G% E - mem_base = ioremap(SHARED_BUFFER_ADDR, SHARED_BUFFER_SIZE);5 ^2 }2 f U3 a2 k9 y0 J) D
- //共享内存初始化
9 p; v8 d2 }# }7 B - SHM_ARM_Init((unsigned char *)mem_base);) n) |, q' _, ~: s
- /*申请中断*/: v9 _$ J+ q# Y
) d& A* @0 z. D- g- result = request_irq(IRQ_DA8XX_CHIPINT0, CHIPINT0_interrupt,IRQF_SHARED,"DSP Signal",&protocol_cdev);
9 p' k8 s. p2 Q! s# V - if(result != 0)
5 e8 k5 d3 q6 R6 Z' j7 [& f' C - {, \! L$ X2 }$ {3 e( y$ [# k
- if(result == -EINVAL)
R# \% B4 a! w - {) B: ~3 z+ f: z& p9 {
- printk(KERN_ALERT "irq request err:-EINVAL\n");
* v9 n; {4 ], g# M2 v/ a& a2 K# A - } `" J& {. D$ T3 w6 _1 m
- else if(result == -EBUSY)8 Q2 M0 O, t3 H. I c
- {( h# W2 X: n( M. b; O8 R' r
- printk(KERN_ALERT "irq request err:--EBUSY\n");
5 ~$ T0 t- M G0 Y+ p G0 W - }0 ~' ~. _( t; C/ Z5 e1 j6 C
- else( B, q2 t% `; {- m" J
- {
( `6 e2 x8 J( R+ p$ W" |/ M - printk(KERN_ALERT "irq request err: unknown\n");; |' b$ i' \9 w% a* n% A2 ]( W
- }
% V. D& j2 r% [. R - return result; I% @8 z- r0 h P; E2 b% C" G4 |
- }
* v3 t0 y5 L1 ], V9 m - return 0;" g$ C- M4 K" i! h9 Z
- }
6 ]2 W. @3 G; ?' p: d - 7 C$ `. w t2 R1 K; y' q# p- A
- /*设备驱动模块卸载函数*/
: ?1 n/ C8 x# h5 u - void __exit protocol_exit(void)
2 s: q) m8 x2 [6 M; ~. T - {
6 [/ h9 f$ W9 }; m* \- O - /*释放中断*/
^. V6 C9 _5 x) q& o - free_irq(IRQ_DA8XX_CHIPINT0, NULL);3 l+ i8 K2 M. l/ d" H& l3 f7 f! _
- //释放帧缓冲的内存& @6 M; G. Q6 Z# ^
- k_linkQueue_release(&queue);
9 x. W6 B: S+ L$ i - //释放寄存器映射
$ n$ i) D+ {% \( o D" B - iounmap(R_CHIPSIG);9 t" u' h# Q' a: t& Q7 s' \. }
- iounmap(R_CHIPSIG_CLR);
& \4 v5 W4 F8 u - cdev_del(protocol_cdev); //删除cdev
8 e- |! Y: \- }3 ]$ l - unregister_chrdev_region(protocol_dev_no, 1); //注销设备号& E8 T1 D& M' w( z0 z Y5 x
- device_destroy(protocol_class, protocol_dev_no); //销毁设备节点( b. N6 w9 [3 R, S$ @7 a
- class_destroy(protocol_class); //销毁设备类
% u' l) G0 g3 Z$ V - printk(KERN_ALERT "exit success\n");
0 M1 J( Y6 F0 `, J1 K( u
% p; y# W9 t* Q8 l+ k) ^- }
; r2 f% J+ V9 x - //驱动其他部分省略
复制代码
- E& ]$ ~" @4 b
5 ?2 `( D* G7 l {- T |