|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
在上一节里,我们在中断的基础上添加poll机制来实现有数据的时候就去读,没数据的时候,自己规定一个时间,如果还没有数据,就表示超时时间。在此以前,我们都是让应用程序主动去读,那有没有一种情况,当驱动程序有数据时,主动去告诉应用程序,告诉它,有数据了,你赶紧来读吧。答案当然是有的,这种情况在linux里的专业术语就叫异步通知。
4 O4 F7 d j% W! N6 v; W' W6 J; n7 ?$ Q# m* _: } r( \2 i3 c
上一节文章:
' ?, C/ D, W$ j* ~5 b) C) }3 M7 C$ z* R4 c/ d9 M3 p
* b' Q. h3 I1 Z7 f在这一节里,我们将在上一节的基础上修改驱动,将其修改为有异步通知功能的按键驱动,目标:按下按键时,驱动主动去通知应用程序。1 y7 f% O$ c2 S
H7 `! D* N: f7 R# B/ j问:如何实现异步通知,有哪些要素?
# X2 ?: A; J( [# F8 L& r# }6 C7 M" [
' B3 o4 J* V7 @) x9 W" ]答:有四个要素:' T; ^) h1 H, c! J
: o# C) E( J. p" y% H9 y7 s
一、应用程序要实现有:注册信号处理函数,使用signal函数# \$ o7 y% G v( }# G
9 L0 T: V5 P+ W
二、谁来发?驱动来发% j, I( Y2 D* p& `6 Y' n
4 c6 y9 ] ?# d! k. |) A三、发给谁?发给应用程序,但应用程序必须告诉驱动PID
# V0 {' X, l2 U
7 L, \0 j) y8 H6 G3 e/ V% }6 o, ?# S四、怎么发?驱动程序使用kill_fasync函数
( i m3 X# b' b. C8 ]4 _$ k8 h5 z. Q6 Y+ {) s" Y. p
问:应该在驱动的哪里调用kill_fasync函数?
9 ~8 w0 Z, C/ v" L# A; _( p& I9 S, `& p& H, A. |. c
答:kill_fasync函数的作用是,当有数据时去通知应用程序,理所当然的应该在用户终端处理函数里调用。
5 u; V7 |! N9 d7 o% U- D% r) \: y" F) O& o+ }4 B" X% _
问:file_operations需要添加什么函数指针成员吗?
: G* y/ t3 k) O
4 @ Y% S0 @8 j, [答:要的,需要添加fasync函数指针,要实现这个函数指针,幸运的是,这个函数仅仅调用了fasync_helper函数,而且这个函数是内核帮我们实现好了,驱动工程师不用修改,fasync_helper函数的作用是初始化/释放fasync_struct4 ^& X: x! }' B1 h2 P5 B* ~) F8 _3 t
, K5 n Y6 i q/ ~' S) N; B& m
# Z2 f. k( }, d0 j; S: t/ V$ h9 W
详细请参考驱动源码:6 H( D& i7 h8 w% E) T* {
# C3 Z9 }$ U- f/ I9 G o
$ o+ c7 ~/ ]! c- [, B& F. W- y#include <linux/kernel.h>* m f3 a- e: p" E* A
#include <linux/fs.h>+ w8 O1 @* s u1 o
#include <linux/init.h>
4 w. a" K2 _4 g2 t: L! \" R( K#include <linux/delay.h>
( g9 h6 Y6 d5 O0 j# C#include <linux/irq.h>' q' U2 y2 p+ q+ P* d2 P: X
#include <asm/uaccess.h>' ?3 V' ^3 j( ^
#include <asm/irq.h>
! W; C6 y; x4 }# Y#include <asm/io.h>2 `# e6 ]6 `0 E* B
#include <linux/module.h>
4 N/ o" g- m |3 t" H2 [#include <linux/device.h> //class_create
7 o: _1 K0 C: M$ X1 s" K#include <mach/regs-gpio.h> //S3C2410_GPF11 ~) i% G9 {/ Q* m e
//#include <asm/arch/regs-gpio.h>
3 k/ q( F) e$ z i& m4 t1 t#include <mach/hardware.h>9 M4 j7 I# Y4 e: g' h0 V, l/ Y! V
//#include <asm/hardware.h>
! ]! X, O; r4 `0 _3 X, ^0 m$ q#include <linux/interrupt.h> //wait_event_interruptible
) ^& \! d2 }, k e4 P- w" {#include <linux/poll.h> //poll, s6 ~" r. U3 K9 A# i
#include <linux/fcntl.h># W3 s6 i0 g" Q. L
1 ?. |2 D! L# W( X. _0 ]7 U, E) W% e- K H
/* 定义并初始化等待队列头 */9 U W8 L8 O( K: [; `* L$ q
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
5 g/ ]5 a7 T/ @
# i% K f+ u" B- b5 S
* Q# t" Y% d0 |static struct class *fifthdrv_class;: ~0 O0 M0 O0 Y; B7 t$ s9 {1 f
static struct device *fifthdrv_device;
: I. d3 V9 ]+ }4 A$ f/ P# R* \
5 d# q5 g7 D4 astatic struct pin_desc{
7 M/ X1 X7 T2 ^ unsigned int pin;# a$ w$ B/ `+ J9 n
unsigned int key_val;$ a5 O5 i, Y9 M/ L, P% S
};
0 Z" D0 C. V/ k( t: Q# h
! A5 [5 I4 W( a8 t# Ustatic struct pin_desc pins_desc[4] = {6 }" p' D2 U5 e$ Q3 k
{S3C2410_GPF1,0x01},* T. S% g2 W1 w9 k' `/ ]
{S3C2410_GPF4,0x02},4 X& [: P! s( X
{S3C2410_GPF2,0x03},4 x, `+ V( e- x7 [1 @+ W# ]
{S3C2410_GPF0,0x04},
0 j. y+ V- a$ `4 A( I}; 0 g5 f2 ^! H( B
- l( d% A% k; C- X1 ~; Astatic int ev_press = 0;
. o% }7 H. A. j! R8 @8 J# A: c7 f. l$ r6 n
/* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */
2 F" }1 \. l: E% p/* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */
Q1 P- T9 E9 r( a9 a( \, Vstatic unsigned char key_val;
) Y& l0 Q4 i4 Nint major;
& ]8 u: \5 D+ I) s0 ^, n% v0 h/ H
- O6 J E) T/ b/ _, ~4 Qstatic struct fasync_struct *button_fasync;) w w: b) b" k
R9 ?" g* ^+ D) D9 k
/* 用户中断处理函数 */" }& @* O. v" |
static irqreturn_t buttons_irq(int irq, void *dev_id), K A6 V9 Y8 Z
{
% ]: K% U* N/ r6 C7 O- Q" i struct pin_desc *pindesc = (struct pin_desc *)dev_id;
# P! [3 l2 G# F* O1 k unsigned int pinval;
; V* G0 Q& Z$ n) k pinval = s3c2410_gpio_getpin(pindesc->pin);; t( K4 r* t" C5 g
# }& R) {3 |. f- k! \& u if(pinval). T* f$ d: |4 R# y( I: C
{
: `% b: x/ G s8 U! J /* 松开 */5 W" D; |9 b, q% j( Z# P* J
key_val = 0x80 | (pindesc->key_val);
, b. s0 }0 U" w2 x1 G }0 Z6 y" R/ o* T1 Y, J) }
else" f. ?' g0 v) r6 K
{) J$ {3 _' L2 W
/* 按下 */
% Z* D0 r/ H; a$ v& A! z key_val = pindesc->key_val;
' Q. [0 [5 g- l6 I D }
; T2 S3 Z8 N) N& c) ?9 K, `/ u6 ~9 N
ev_press = 1; /* 表示中断已经发生 *// `6 o G) r5 |0 V$ j/ w- c
wake_up_interruptible(&button_waitq); /* 唤醒休眠的进程 */
Q) ]$ x7 J5 g2 R2 I0 K0 U u& l: n. c
/* 用kill_fasync函数告诉应用程序,有数据可读了
: ~ D1 @6 L- b# y * button_fasync结构体里包含了发给谁(PID指定)) O) p! s \" W. r. o
* SIGIO表示要发送的信号类型' @1 R: u2 u7 s4 r& H1 r6 m2 ?
* POLL_IN表示发送的原因(有数据可读了)
/ K" k/ b; Q! ~; Q */9 v: k; a! G4 V4 Z! _% S* p8 d
kill_fasync(&button_fasync, SIGIO, POLL_IN);$ g }1 A. o* e! ?7 S
return IRQ_HANDLED;6 q! o+ D5 [& L; F% @* @ Y& S
}
' w7 P2 L8 M2 v" f7 ~4 o* [" m7 f$ _static int fifth_drv_open(struct inode * inode, struct file * filp)1 e) k7 V, Q- m/ c3 W
{
- e7 \: {" N* W) {4 t /* K1 ---- EINT1,K2 ---- EINT4,K3 ---- EINT2,K4 ---- EINT0; U2 f9 |8 Y4 Q3 ]) C T" g' w9 @5 m
* 配置GPF1、GPF4、GPF2、GPF0为相应的外部中断引脚5 d K }" i* d9 w7 z
* IRQT_BOTHEDGE应该改为IRQ_TYPE_EDGE_BOTH
j F- [8 J5 d+ P5 i9 W" n4 w */
7 M$ [, Y/ \) A" E5 j! B% T1 x request_irq(IRQ_EINT1, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K1",&pins_desc[0]);- n9 K& y: u) @0 ]% l! L: D! h3 w2 _% U
request_irq(IRQ_EINT4, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K2",&pins_desc[1]);0 z+ Y2 `* g, l2 L4 t/ Q- A
request_irq(IRQ_EINT2, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K3",&pins_desc[2]);( ?+ Q$ D/ @ O# N
request_irq(IRQ_EINT0, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K4",&pins_desc[3]);
! ]% c$ d! F" n+ I- X, I return 0;2 W- y3 B+ I6 t. N% ~
}, A, g& c7 w; q6 L8 ?) N
/ D. Y- h& `5 {0 f; F- astatic ssize_t fifth_drv_read(struct file *file, char __user *user, size_t size,loff_t *ppos)
/ D; y$ F7 q7 u1 c3 d. G{
$ F% G+ r1 |/ B5 q; k4 b) Z/ V if (size != 1)
0 P6 K( O1 y/ a" }2 {" r* y2 u: E return -EINVAL;
* g! c4 ~( J2 k# h, G+ b
# w) l# C, l: O8 q /* 当没有按键按下时,休眠。
: A/ F' X; T, s+ o0 t- L * 即ev_press = 0;
' i: v' F% \, }5 C; _9 z * 当有按键按下时,发生中断,在中断处理函数会唤醒1 B6 k) g- Y; D$ [3 N8 T; ?
* 即ev_press = 1; # R# |/ _5 g& f* R9 [" R6 p2 n1 v+ M% A: y
* 唤醒后,接着继续将数据通过copy_to_user函数传递给应用程序) U3 m4 `3 A$ q# E3 r
*/
) @$ M3 w$ M0 @! [# B3 a wait_event_interruptible(button_waitq, ev_press);% m* c; d+ F+ f
copy_to_user(user, &key_val, 1);
4 A# ^3 I" i. S4 ]* J- R- p
3 P0 R, W! W; \1 M5 j /* 将ev_press清零 */
# X; ^) W; k5 J1 T# B" z/ j ev_press = 0;
$ r2 l. v2 w) T return 1;
+ I' }& S# z# |4 G}
3 ?. M( i- \3 O' j8 N ^% r, k
) X, ?0 A5 ]6 rstatic int fifth_drv_close(struct inode *inode, struct file *file)
\- D! O+ c. r2 R: t6 s{- I( B7 S7 D& l; |
free_irq(IRQ_EINT1,&pins_desc[0]);' W$ u+ D5 h0 z5 G
free_irq(IRQ_EINT4,&pins_desc[1]);* y0 t* Y/ i' `- J. E! |
free_irq(IRQ_EINT2,&pins_desc[2]);
* w5 ?; A' B/ l% u( [ free_irq(IRQ_EINT0,&pins_desc[3]);
5 q2 U) C; `& V5 v return 0;" Y- a8 |3 ~ A1 J
}
4 {0 } ^/ o) {! W, u3 p
& v+ k# Q: H4 \) S" Fstatic unsigned int fifth_drv_poll(struct file *file, poll_table *wait)
5 L3 n+ g! K$ h4 E, f{4 k) k. d' m4 Z9 [$ x8 T2 u* D0 q
unsigned int mask = 0;
, J2 ^3 m3 j3 o5 A2 _7 M
0 F. e' l L* a( Y/ t9 w. b) u /* 该函数,只是将进程挂在button_waitq队列上,而不是立即休眠 */, k; W7 k$ P1 m' G2 I% r
poll_wait(file, &button_waitq, wait);
9 S. m5 h, f, l% a+ i) [2 K0 T* O1 R1 [0 |; Y
/* 当没有按键按下时,即不会进入按键中断处理函数,此时ev_press = 0 5 {2 ]) o: j* n$ Q7 O9 y. R& t* C
* 当按键按下时,就会进入按键中断处理函数,此时ev_press被设置为1/ j& S5 u: g$ D+ \
*/
! p' g# ]3 i2 l' E5 K# M5 { if(ev_press)1 q; ]4 _- L/ \6 u
{8 D+ c" o) ^# f. d3 z6 g
mask |= POLLIN | POLLRDNORM; /* 表示有数据可读 */2 m' z* X5 s; E, m! F9 }. R2 ~
}
# ?4 M5 q: j- H, r0 o L: _' C& m e
/* 如果有按键按下时,mask |= POLLIN | POLLRDNORM,否则mask = 0 */ Q) h) r: x3 i
return mask;
* v9 I/ D' j5 W- i3 ^}) ~; T1 Y1 e" v7 M4 j
* ^2 C4 q2 N7 ?/ b2 b) b/* 当应用程序调用了fcntl(fd, F_SETFL, Oflags | FASYNC);
: n* f+ o' }$ y7 ]( W * 则最终会调用驱动的fasync函数,在这里则是fifth_drv_fasync
* Z5 j$ b- f$ c, o * fifth_drv_fasync最终又会调用到驱动的fasync_helper函数
4 Q0 F4 D' k! ^$ Z3 G) ? * fasync_helper函数的作用是初始化/释放fasync_struct
. f% w% X9 l, Y5 c1 C3 ^ */5 l0 T, \: S; O- {6 ?: ` _
static int fifth_drv_fasync(int fd, struct file *filp, int on)- Z! n! x% S- q9 d! V
{
$ Q, ^; Q# c8 g( H6 Q return fasync_helper(fd, filp, on, &button_fasync);0 @+ x& j' h9 W
}
) r( V& m' C; O: E: |9 I- w
& o* H2 n. @5 e4 s- e/* File operations struct for character device */- y l, \2 O: P4 T
static const struct file_operations fifth_drv_fops = {
* G7 S) w1 E& ^; r9 l o, k0 b0 @ .owner = THIS_MODULE,- c, U/ J y* ~$ F( g4 N
.open = fifth_drv_open,* s6 [* L" ]# z) ^% }
.read = fifth_drv_read,
+ C i" P, b0 d7 Y8 } .release = fifth_drv_close,0 z% y: s9 B- q. n# R
.poll = fifth_drv_poll,
u, m8 D4 L' B .fasync = fifth_drv_fasync,
: r |3 Y& Q% }3 J6 h};6 K2 I) o3 o8 P6 B8 H9 I
. y7 V+ ]& j# f2 P7 M5 r% w7 }
6 q$ A" T2 Y9 e2 R7 |$ H6 d/* 驱动入口函数 */
1 }& O; t/ N) Q8 z1 i( P3 ]% `8 Bstatic int fifth_drv_init(void)
$ i: C$ O# w, f- O8 o1 N{
; N+ d7 m' b8 x/ e- \ /* 主设备号设置为0表示由系统自动分配主设备号 */7 V9 S- w1 L1 |7 ]! W/ u0 _
major = register_chrdev(0, "fifth_drv", &fifth_drv_fops);
3 P, A8 c4 A; V" B
: Y2 a: b" U: ~8 }1 l: g /* 创建fifthdrv类 */2 v2 \/ M' o/ k, L3 ~- I
fifthdrv_class = class_create(THIS_MODULE, "fifthdrv");% ?7 q: B: x: q8 y
1 {$ b" _' K2 i) q /* 在fifthdrv类下创建buttons设备,供应用程序打开设备*/
& t6 Z) T5 J8 q0 H fifthdrv_device = device_create(fifthdrv_class, NULL, MKDEV(major, 0), NULL, "buttons");
* V d$ Y# O9 }" P* ?
2 z4 \8 ]- Q% ^; `4 i7 | return 0;/ U7 Y5 O2 {3 {
}
% z0 P$ y' x; h; X5 u& A
, H+ o9 F: j, e: f; \' a/* 驱动出口函数 */
/ h" C% v7 I5 |static void fifth_drv_exit(void)5 ~7 M' {) V4 R$ d! p
{
7 T. W X% T/ ] unregister_chrdev(major, "fifth_drv");
5 v9 w6 X0 C0 S: ^: n device_unregister(fifthdrv_device); //卸载类下的设备
& k: S5 @+ e: A1 s class_destroy(fifthdrv_class); //卸载类5 n" Y8 ]. c& n5 Q* V: s
}" U& q; \; j, R0 t% l* P/ g. ?& W
: z% J( {$ D1 [) e8 F+ fmodule_init(fifth_drv_init); //用于修饰入口函数
$ G$ {9 w" K4 W1 @3 z6 _) G- d7 Gmodule_exit(fifth_drv_exit); //用于修饰出口函数 & Q* q* ^) @ Z5 I
8 f5 ]+ e% p5 i! v* N
MODULE_AUTHOR("LWJ");0 r" J8 R( g+ s" d3 y: \
MODULE_DESCRIPTION("Just for Demon");
7 `: Y3 S4 ]7 k; w! C) R' s- EMODULE_LICENSE("GPL"); //遵循GPL协议7 q) G4 h5 k3 b7 x$ q
+ P$ @& S. c0 U) a. q应用测试程序源码:) L' e# }6 l4 b1 w0 `: Q
9 t4 F3 K U9 [) Z! A#include <stdio.h>
! Y0 k/ b$ I& g/ f4 m, K: x2 \! d#include <sys/types.h>9 f h" \5 [2 b/ D" G, X
#include <sys/stat.h>" L) a$ H( H7 d! ^; O1 \' W
#include <fcntl.h>+ ^4 `0 } t! c) q k; t- `7 r0 h+ O& c
#include <unistd.h> //sleep- X8 s# l* Q) V
#include <poll.h>
6 E1 P$ f0 A# N$ P#include <signal.h>
- v5 Q# {& C a) _#include <fcntl.h>) O: q3 ` C! U
$ R" {' l$ K* Z
int fd;
! a# M# U9 j7 O, d
6 `$ C4 Q) C7 R& jvoid mysignal_fun(int signum)
1 w! J' y" K6 W{
% C, d4 }8 [* y/ ~- m$ o: _, m unsigned char key_val;
9 J# |7 ~' o% O4 T" Y* @1 f read(fd,&key_val,1);
3 A2 e3 i! X0 X" o5 I/ y printf("key_val = 0x%x\n",key_val);
% Y' m; k" U" V* o}
, X- \2 I7 t! |3 v) u( ?% i! k& r: `+ _( u1 I/ ]) t
( c8 m2 }. B& B. w0 F, `/* fifth_test
7 ?3 c. c7 Z% o7 R: [1 n+ u, R */ - W, O0 N8 x9 O6 x h( S4 c5 M" e9 U/ K- o
int main(int argc ,char *argv[])
) k" T! j: s$ r) j9 V( C8 @, h# _{$ Z4 U; l6 q- x( u* m4 `
int flag;
S" G+ p6 a3 F8 J, l. u/ f signal(SIGIO,mysignal_fun);( T1 ?' a! j% \ e
n- H1 @5 v3 w" Q. L# t
fd = open("/dev/buttons",O_RDWR);
0 D4 H6 u5 B% q: {" Q if (fd < 0)
" c6 y. ?: _& O {, `4 n/ F6 x& o2 I
printf("open error\n");
- s' V% `) t7 W, A3 B4 I4 @ }' \- A9 ?( v. b3 {+ h/ f8 C
0 K: z4 J: c; y3 r2 v P: v
/* F_SETOWN: Set the process ID- P% s1 L Y' m7 H
* 告诉内核,发给谁
( A5 k# q0 g7 k- q2 U3 o */
1 |) z2 a0 h; H. h7 F fcntl(fd, F_SETOWN, getpid());1 l7 K# K, @- N" \! Y# ]
) B0 Z9 q, ?) y7 b+ q: y# B4 q /* F_GETFL :Read the file status flags
) J* F. l3 j1 z * 读出当前文件的状态: s0 x" |/ P9 b2 O* e! q$ e
*/
3 n$ j1 I" L* g* a0 L6 Q flag = fcntl(fd,F_GETFL);
: C* p* W/ W/ l& O* F. o5 a
d* s3 A% G j9 a. i& @9 g1 }, p /* F_SETFL: Set the file status flags to the value specified by arg# A2 h- N Z. `
* int fcntl(int fd, int cmd, long arg);
/ @: G9 j% J$ n% U* @ * 修改当前文件的状态,添加异步通知功能7 N% K0 `+ N& B0 `; R5 ]8 H5 E
*/
" R) n, ?' s$ r g% ] fcntl(fd,F_SETFL,flag | FASYNC);( K5 T0 w" [; B1 Y; U- d. P {
$ ?( O4 _$ `6 ] while(1)
* o' u% \6 ]2 Q! P z {
9 N7 [4 p$ l+ |) ]9 H. ~8 F% U( M( j /* 为了测试,主函数里,什么也不做 */
) S3 u$ O5 @/ {9 S sleep(1000);4 E O# B4 W% P9 e2 s
}
3 ]. ~! ^# U7 s; X" o ~9 g" v" d return 0; M( m( x" a& w5 ~" j0 c
}8 H/ e9 B" o2 T9 f: C' a5 L
x- j+ j& ^& [% s! ?测试步骤:
6 w+ S/ w3 n* Y
: o9 T' K3 f1 W7 V% Z; V3 a- d7 W[WJ2440]# ls
( H B% H" ]# hQt fifth_drv.ko lib sddisk udisk
6 I2 n) M7 s7 T, p' E* U! xTQLedtest fifth_test linuxrc second_drv.ko usr
/ d w) |7 N% t( ] \. iapp_test first_drv.ko mnt second_test var5 C0 V; W0 }! H+ E+ N/ b' X' I
bin first_test opt sys web
7 _/ Y/ [0 `; L3 x0 k5 Ydev fourth_drv.ko proc third_drv.ko* g- Y0 d# `9 o
driver_test fourth_test root third_test' ]) e, }) T) K# t6 s. r* R6 H: X
etc home sbin tmp; f4 i! G/ _% s1 _0 Y/ H
[WJ2440]# insmod fifth_drv.ko ) y& k6 g2 s# O K" ~7 z
[WJ2440]# lsmod; v% l# B' r8 P3 D& M3 u- P2 x
fifth_drv 3360 0 - Live 0xbf006000. F) s+ Q7 q2 K. a7 t
[WJ2440]# ls /dev/buttons -l0 u& ^3 c4 o" [ f7 T; {6 \
crw-rw---- 1 root root 252, 0 Jan 2 04:27 /dev/buttons
1 d1 A* Z& G% l( x7 B[WJ2440]# ./fifth_test
' c# I2 ]0 c$ b1 Q3 F7 Y# t4 okey_val = 0x1
" L! N7 L+ r& G/ y3 U% P& Tkey_val = 0x81
( Z! x+ B% A* L2 w F3 ?key_val = 0x44 \3 |! b; J/ F- r. P( r; r
key_val = 0x849 Y& t, R$ C) R) m. B. n
key_val = 0x2. S: o' i% G+ L; L1 j
key_val = 0x827 K, K/ O0 G# G0 P1 r) {" X
key_val = 0x3
9 ]: C' w3 z3 O. C. Ekey_val = 0x83( M1 z) j6 y& L
key_val = 0x4
# m" o& M- p' @- Gkey_val = 0x846 r$ O6 h& `+ d/ v7 \ ^3 L4 q5 [' U
key_val = 0x84
* P5 d+ T. b% R* o% y$ `( ^+ [7 J
& v' }2 s0 P1 C" U3 g5 ^$ s由测试可知,当无按键按下时,应用测试程序一直在sleep,当有按键按下时,signal会被调用,最终会调用mysignal_fun,在此函数里read(fd,&key_val,1);会去读出按键值,这样一来,应用程序就相当于不用主动去读数据了,每当驱动里有数据时,就会告诉应用程序有数据了,你该去读数据了,此时read函数才会被调用。: p- C7 y* k: R
/ C7 B! K: U- v9 d N; C0 s: p7 C* d7 |+ x. r, S& Y
这里最后总结一下老师的笔记:
# a, a* U9 [# O# g' k' L
8 s9 @9 I. C: @为了使设备支持异步通知机制,驱动程序中涉及以下3项工作:5 ], C5 l, Y# n
1. 支持F_SETOWN命令,能在这个控制命令处理中设置filp->f_owner为对应进程ID。6 {' v9 Q* Z# Q/ ?$ J5 y2 [& g4 z
不过此项工作已由内核完成,设备驱动无须处理。6 {' E. K( G0 c/ @+ A$ F
2. 支持F_SETFL命令的处理,每当FASYNC标志改变时,驱动程序中的fasync()函数将得以执行。
* \" I; W" E' M' _ 驱动中应该实现fasync()函数。0 X- v6 ~, I% M4 b+ d& C8 H2 Z5 `
3. 在设备资源可获得时,调用kill_fasync()函数激发相应的信号0 S. V* c4 p1 |5 w, S$ Q" O. c
# T n( P6 d' H# M n6 L' ]应用程序:
$ ^# {; I4 ~0 w! r2 _fcntl(fd, F_SETOWN, getpid()); // 告诉内核,发给谁
+ }- g& W! @! k
, \4 K- M3 m, |% B7 l3 KOflags = fcntl(fd, F_GETFL); 5 h/ V# H2 y, ?8 k7 U6 q1 i
fcntl(fd, F_SETFL, Oflags | FASYNC); // 改变fasync标记,最终会调用到驱动的faync > fasync_helper:初始化/释放fasync_struct% w# ]' }! y! O7 o
$ i( S3 [% n& v. f3 N# }" j* V
, L; z4 J! U! Z Z3 U0 S" M7 Q
+ I7 f; B% D7 P0 s/ F- e |
|