|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
在上一节里,我们在中断的基础上添加poll机制来实现有数据的时候就去读,没数据的时候,自己规定一个时间,如果还没有数据,就表示超时时间。在此以前,我们都是让应用程序主动去读,那有没有一种情况,当驱动程序有数据时,主动去告诉应用程序,告诉它,有数据了,你赶紧来读吧。答案当然是有的,这种情况在linux里的专业术语就叫异步通知。; Y" d+ E. A( \
0 ?4 Y$ J& J( N3 ]4 V5 r上一节文章:3 P2 P- j7 [: ~
* J7 o* M0 v! g. S1 F0 C9 b7 r
! J- h" W* Q8 f5 B; A在这一节里,我们将在上一节的基础上修改驱动,将其修改为有异步通知功能的按键驱动,目标:按下按键时,驱动主动去通知应用程序。$ v" \9 q) C6 }$ @. m H T
: x3 Q5 d+ U% R# X% P问:如何实现异步通知,有哪些要素?8 y. i$ R$ w( d
+ d$ O' w; j) _: x B4 l* H
答:有四个要素:" Y( h) }3 h: v# M9 w! B; D
4 z+ i) Z6 T, i8 K$ b一、应用程序要实现有:注册信号处理函数,使用signal函数% C! P1 T2 o5 j- y P$ A; E
7 n& n, j) K% e8 y8 I( Q二、谁来发?驱动来发 ]1 s; _3 Q) {% W% t
/ Q' a/ z! K# q8 Z& g- e4 N三、发给谁?发给应用程序,但应用程序必须告诉驱动PID/ i9 A* r' G; m' t8 L. Z
: A! e `8 }# c四、怎么发?驱动程序使用kill_fasync函数# r6 N, [9 p D& J& c- X6 d
0 U, L! q. z8 e1 M
问:应该在驱动的哪里调用kill_fasync函数?# \( @3 l) f+ d8 `
" _' T4 }# o" Y0 k' o( J答:kill_fasync函数的作用是,当有数据时去通知应用程序,理所当然的应该在用户终端处理函数里调用。 Y+ N; N' J( e/ M; r1 G) s
4 r6 Y8 V; c+ ~4 M6 V$ N
问:file_operations需要添加什么函数指针成员吗?- d# x2 o u7 F V2 y
- n, a3 y2 ]' h6 O- p9 ^ Z& I, i
答:要的,需要添加fasync函数指针,要实现这个函数指针,幸运的是,这个函数仅仅调用了fasync_helper函数,而且这个函数是内核帮我们实现好了,驱动工程师不用修改,fasync_helper函数的作用是初始化/释放fasync_struct4 u$ G2 z* [/ V( Z' m! Y; P% p
! z, m( t5 _0 [
( Y( r2 S8 k5 ^: X/ {# m* b3 ?2 x
) y0 m8 e j! G2 G! Z8 y详细请参考驱动源码:2 x7 {3 Y/ |1 J# m- h: x! c
8 Z$ b- U6 E( u$ o
! U3 m; _: A; K+ d9 R#include <linux/kernel.h>
: O2 ~6 B. Z* [ U3 G/ I#include <linux/fs.h>
: [, P7 u' i) m9 z& r#include <linux/init.h>4 l B9 t9 O. l
#include <linux/delay.h>3 _5 }* k/ q' x, ^: D
#include <linux/irq.h>; R4 L' b: L/ O9 L6 i5 r
#include <asm/uaccess.h>" J5 H# c( Q1 n
#include <asm/irq.h>% c5 b; U/ x& d. B3 v8 E0 n
#include <asm/io.h>, Q- B$ M- h6 f% ? F7 Z
#include <linux/module.h>
. \( Q$ @6 e& {( R#include <linux/device.h> //class_create
% U, f& m9 p0 q. J! F#include <mach/regs-gpio.h> //S3C2410_GPF1* Q( ^6 C( B c# U
//#include <asm/arch/regs-gpio.h> ) C* S1 [* s( u# ~
#include <mach/hardware.h>
+ l5 l- m8 g4 }$ j//#include <asm/hardware.h>+ O ?$ q# @9 O
#include <linux/interrupt.h> //wait_event_interruptible$ y5 p7 N5 i* v1 v# v1 h/ k
#include <linux/poll.h> //poll) S: r8 [( J2 Y; g8 k6 a
#include <linux/fcntl.h>
0 Z" Y7 H; q( O6 `5 g
+ [, D5 k: o9 Y: O4 m) y5 F, b& ?
/* 定义并初始化等待队列头 */
9 j) z9 `- J7 p2 R6 jstatic DECLARE_WAIT_QUEUE_HEAD(button_waitq);
& H& U% K5 e% W4 q- N
) d6 r' A8 f% T7 d1 U
) O; X1 [- I5 \6 bstatic struct class *fifthdrv_class;# b. K2 o9 c$ L+ |- u
static struct device *fifthdrv_device;
2 h: _6 Y) g; ^+ M1 n/ n/ t$ U6 Y: h3 l1 C6 X% @# y
static struct pin_desc{* C: \7 I8 p& t" D+ a5 B
unsigned int pin;
9 b6 y# | E! J7 x, |) B. T8 B unsigned int key_val;7 n8 A7 e6 S. W6 ]6 A0 @9 O
};
" L6 g# P ^; ~$ R9 ^7 J" `5 q6 N/ w) S( |
static struct pin_desc pins_desc[4] = {
3 X# R1 J5 n# t9 u, Q {S3C2410_GPF1,0x01},
6 ]; E; v2 |, N/ h6 r: D {S3C2410_GPF4,0x02}, t3 J, d7 D/ H( b6 f
{S3C2410_GPF2,0x03},. s& P) J4 Z( O! N" h2 T# ^5 B
{S3C2410_GPF0,0x04},; H7 k7 P. c3 m! _9 a, \) v* b( W
};
B# O! `# l0 z' E5 r
- C% _+ a; T0 \5 _static int ev_press = 0;- E3 k4 q/ W" l4 I6 |) D7 ^
$ o0 l3 ?. S' H6 z$ q/* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */0 l. t$ a' y( x' J0 I2 b
/* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */
0 Z, l2 `1 W" o+ t# Z0 Vstatic unsigned char key_val; c! Q$ E$ H' i8 O& B J w
int major;
) ]9 t! T' E* ]6 d2 X1 F) k3 Q& C2 r
static struct fasync_struct *button_fasync;
+ k& }3 L) f8 _. i6 |& O& ?+ h0 w
6 C! N" j8 ^" r* P" d: v4 t/* 用户中断处理函数 */( E* X2 U/ S4 V
static irqreturn_t buttons_irq(int irq, void *dev_id)$ j; g# H) m1 z l" J' d
{ S- f+ V# a4 w$ }
struct pin_desc *pindesc = (struct pin_desc *)dev_id;/ w) P3 L" N& }
unsigned int pinval;+ D9 g4 H! c q2 W( |
pinval = s3c2410_gpio_getpin(pindesc->pin);) b q0 x8 ~* D% j: f: u
& H" r1 F/ u4 V5 D2 g
if(pinval)
% c1 } l5 _) R4 |$ ^9 M { f+ g4 {/ B6 r# H9 ^
/* 松开 */# s2 k8 Y- ?( o1 I( e% b/ x
key_val = 0x80 | (pindesc->key_val);* n' ~+ u% Y! \ {& s) D
}
' z" z) e+ `0 U( ^ else
) l4 o. r% I- g- M, m4 W+ p {
- d- P% D! \, _- r$ v' o/ _ /* 按下 */: M1 z9 N; X) H# b. {
key_val = pindesc->key_val;
% k- K# m% l2 ?# ~. w }( ^( N' ?! J3 L
1 ~9 p: [0 Z. b2 Y/ V' A ev_press = 1; /* 表示中断已经发生 */
7 l# |: G- p r: V9 @: ? wake_up_interruptible(&button_waitq); /* 唤醒休眠的进程 */5 o& R8 |' e) M# b# ^( Z
9 b z2 I, X9 e* a
/* 用kill_fasync函数告诉应用程序,有数据可读了 + T& _/ t5 u# ?
* button_fasync结构体里包含了发给谁(PID指定)0 Z v/ P. P# A1 V$ D+ W7 z
* SIGIO表示要发送的信号类型
4 {' G7 O4 f* {$ w @ * POLL_IN表示发送的原因(有数据可读了)
5 v6 S' y6 D, c3 F8 | */6 V: ]8 W$ {5 i- M
kill_fasync(&button_fasync, SIGIO, POLL_IN);
; g( f# E; Q* O% j. F, y return IRQ_HANDLED;
# \+ c+ G( B8 O/ T7 o" O3 W2 c}! \( L2 i5 N9 b: o2 M
static int fifth_drv_open(struct inode * inode, struct file * filp)7 E+ ?8 y/ O' ^: ?4 I' x
{0 H. r, n+ i" a& I6 H9 o0 L
/* K1 ---- EINT1,K2 ---- EINT4,K3 ---- EINT2,K4 ---- EINT0
% ]- Q6 v" o: L2 r * 配置GPF1、GPF4、GPF2、GPF0为相应的外部中断引脚/ G' Q/ n Q; P# n A: e
* IRQT_BOTHEDGE应该改为IRQ_TYPE_EDGE_BOTH
4 q- x- l4 R. S4 e */* G9 h6 H' j: h
request_irq(IRQ_EINT1, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K1",&pins_desc[0]);5 F$ H" o; F/ i. V- O3 Q
request_irq(IRQ_EINT4, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K2",&pins_desc[1]);
; t# g) a* h: V# Q0 l, S& c; C request_irq(IRQ_EINT2, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K3",&pins_desc[2]);4 r+ Y$ p1 H$ i4 B: W; k; C/ Z
request_irq(IRQ_EINT0, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K4",&pins_desc[3]);, ^ r5 {6 s7 ~* U: j1 E; w
return 0;4 t6 @/ t; r" X7 `4 e
}' [6 A* h" h4 R' I: B1 P. p! p0 H
0 U+ j) i P* f$ R$ Z) Cstatic ssize_t fifth_drv_read(struct file *file, char __user *user, size_t size,loff_t *ppos)
G, F8 d' }* \3 c; j* N{
1 h; M U2 L( u4 d$ i( [/ d, R if (size != 1): p3 p6 I8 n$ b$ m
return -EINVAL;
- e' H# g, c- i. n& v6 l
. i2 o3 D8 D& w2 j /* 当没有按键按下时,休眠。
5 E$ f9 e; O% ^ * 即ev_press = 0;- U/ k' W* }3 x: B% {
* 当有按键按下时,发生中断,在中断处理函数会唤醒
: L* A/ M ^; G% U* F' n5 }& {& [ p * 即ev_press = 1; + t X4 y! S. S: w5 i1 @
* 唤醒后,接着继续将数据通过copy_to_user函数传递给应用程序
, J$ s7 e; r* `; ^1 B */ d$ p! c& j U- B+ E. W
wait_event_interruptible(button_waitq, ev_press);; i4 C; ]6 Q o% M& \
copy_to_user(user, &key_val, 1);1 R6 L; `) j9 I( r3 ~
6 u0 ~5 t" C: j# ?- @ /* 将ev_press清零 */6 I. O I T" h6 r& z& y+ I: {
ev_press = 0;
1 ? Q% m8 V( Z$ r return 1;
" r$ y8 [( a6 E0 e7 C: x. |}
2 K( F* f1 X) w& c
& p4 P& L( ?$ F$ u$ S; Tstatic int fifth_drv_close(struct inode *inode, struct file *file)0 M) w. G3 u/ ]9 t9 s5 A6 N
{. i& Q5 y3 R/ m
free_irq(IRQ_EINT1,&pins_desc[0]);
3 ~' ], e. t8 ?: t free_irq(IRQ_EINT4,&pins_desc[1]);# H! X& q, T# a2 ?- g
free_irq(IRQ_EINT2,&pins_desc[2]);
1 T/ ~1 L0 u# t6 T Q free_irq(IRQ_EINT0,&pins_desc[3]);5 }: e7 m8 v9 ~! C N
return 0;
. J( H$ R. X/ c# a E& f}) w% e* j, `7 o
" ?6 {% `% _3 zstatic unsigned int fifth_drv_poll(struct file *file, poll_table *wait)
" X$ p8 n( w! p6 R. O{
9 l0 p- Q( l( J3 N unsigned int mask = 0;% O2 I7 B7 K( m
! ] J, a' A9 }' ^/ E5 f0 s3 @ /* 该函数,只是将进程挂在button_waitq队列上,而不是立即休眠 */; Q: r0 C/ [$ f6 C2 q) ~) K/ \3 H
poll_wait(file, &button_waitq, wait);
l% X6 G$ t0 v: u* n4 k) [3 k; _
1 y% X. G/ l5 Q& [% L& Q9 C /* 当没有按键按下时,即不会进入按键中断处理函数,此时ev_press = 0
7 L9 ^+ d* T, i5 H. m * 当按键按下时,就会进入按键中断处理函数,此时ev_press被设置为1* l/ n8 f/ k* r# K4 G! H' t
*/
~1 `" r' Q, Z) m2 i1 W0 V if(ev_press) Z2 }1 |- g0 ]
{% x- e5 U( ` ]+ p/ W5 z0 ~
mask |= POLLIN | POLLRDNORM; /* 表示有数据可读 */
8 j4 Y4 S7 N4 h3 l& J) `" ]) ]) | }4 s5 O- e, B: C# v! c
2 m, \$ w$ Z0 v$ Z
/* 如果有按键按下时,mask |= POLLIN | POLLRDNORM,否则mask = 0 *// T$ V! @! \* _) A
return mask; ' j: u; x' x% T
}
w1 d/ s% ~3 x' \4 E& z3 J+ `
|7 d7 L# a" o$ Z8 Q/* 当应用程序调用了fcntl(fd, F_SETFL, Oflags | FASYNC);
0 Z4 V1 f' f$ H& X8 V$ D3 g * 则最终会调用驱动的fasync函数,在这里则是fifth_drv_fasync
5 _0 U! T E& V0 S1 U * fifth_drv_fasync最终又会调用到驱动的fasync_helper函数
! l4 Q7 `% z+ s W * fasync_helper函数的作用是初始化/释放fasync_struct* }* z+ c* g: N6 W* w, W0 s/ o. z
*/, S6 k# ~1 c) E- l! o) l( I ?2 n7 s
static int fifth_drv_fasync(int fd, struct file *filp, int on)+ G, T+ `4 Q- F6 O8 c
{
. q9 E3 a. ?8 S: p" K$ j1 I6 X return fasync_helper(fd, filp, on, &button_fasync);
& n) h. H6 a& S! c! T}
6 E: L+ K, @2 m8 H9 I5 k5 B$ O( N4 e4 y6 }- V! w' o1 ^4 C
/* File operations struct for character device */* I6 E% U) Z; x" e, O& \) [: X' O
static const struct file_operations fifth_drv_fops = {
8 u/ P# B& l* f2 T .owner = THIS_MODULE,
8 K, S9 q$ G: R& H8 Z .open = fifth_drv_open,
5 y7 e( y- A% ^' r .read = fifth_drv_read,( f6 i y* q1 t" i/ z
.release = fifth_drv_close,& t+ i0 t: |* i, h$ z
.poll = fifth_drv_poll,0 |1 d7 ^- U- t$ C% [) b
.fasync = fifth_drv_fasync,
1 D/ d; V. u2 K+ O# s5 X& f};3 c2 p9 |4 L0 _# y- c
6 a& N0 h% m- c% B, y) t/ M
0 ?) s. V* [2 `& e/* 驱动入口函数 */
1 E1 h' j0 M* b$ s' estatic int fifth_drv_init(void)
, ?# Q% p5 h5 B$ J T{
) t# Y' o# {! u K /* 主设备号设置为0表示由系统自动分配主设备号 */
7 }! D, Q; e) r! j$ m. u major = register_chrdev(0, "fifth_drv", &fifth_drv_fops);( ^1 j2 [! u5 u) E' F% O
5 p8 N- O* T6 L3 @
/* 创建fifthdrv类 */$ V' W0 }& K8 X8 F7 ^( {, Z
fifthdrv_class = class_create(THIS_MODULE, "fifthdrv");
5 Z2 C- n9 G2 {! {, T2 W2 u
% h/ d! U1 X- F- m7 T /* 在fifthdrv类下创建buttons设备,供应用程序打开设备*/
' y) g: o: B3 W6 f c' v fifthdrv_device = device_create(fifthdrv_class, NULL, MKDEV(major, 0), NULL, "buttons");4 ?- n+ p- S9 }& o" f
[; C( ^: r2 e$ P, R( u return 0;( h; v% a% A5 Z; |
}& ]' X8 `, p6 U, E4 B4 c
& q' ^3 Q# n* [. d% R! T1 V2 ^; h
/* 驱动出口函数 */
! v9 z3 E4 h- zstatic void fifth_drv_exit(void)8 F3 }6 Y) C4 v' q$ ~! ^8 ?, [2 d
{ |+ Y+ ]5 ]6 Z' ]* I8 W
unregister_chrdev(major, "fifth_drv");4 y' Y* w1 }$ T2 y2 w
device_unregister(fifthdrv_device); //卸载类下的设备
& J9 v! Y1 r9 L; m4 S1 j class_destroy(fifthdrv_class); //卸载类
% S! o2 B( D# Q% n. r: s, h7 L" }}. v7 x) Z- k6 X+ w$ ]* C
" Z. H7 v, q/ b F6 p: g+ Hmodule_init(fifth_drv_init); //用于修饰入口函数4 m' w+ a1 v" S" Z/ g
module_exit(fifth_drv_exit); //用于修饰出口函数
7 D U \# M7 p" E" v
; K& R: Y' ]- s3 C! DMODULE_AUTHOR("LWJ");
0 d8 m: A. R" f( d8 r1 H. fMODULE_DESCRIPTION("Just for Demon");
4 ?+ f) M- ~! T0 PMODULE_LICENSE("GPL"); //遵循GPL协议. d- a) N1 @/ Z& v: U6 Z
; t4 A7 P4 z- H. J& }7 i应用测试程序源码:, K) U- C( P) s% g5 A" W' E4 q
5 \' `0 {6 l0 D
#include <stdio.h>
' A7 O2 A- [( _& c# v#include <sys/types.h>
; A; B* r2 K, z5 Q#include <sys/stat.h>6 \ \- O& @* H
#include <fcntl.h>
3 g6 O. p9 _3 H2 K#include <unistd.h> //sleep; v1 I$ b/ c5 U% ]0 R( G
#include <poll.h>
) o; J# ?2 a! K/ G' W#include <signal.h>* @7 E C% ~: b' U
#include <fcntl.h>
# { W! |* W' X H/ V
, V) i) |! J; Z, m8 U Lint fd;0 i c! O2 G% s+ b" ]% d5 J
: \1 F; R# T2 N# Z8 _% Pvoid mysignal_fun(int signum)* _- X b$ a/ N7 i2 I' ~ R
{1 H6 K3 [- ~( \1 l) v
unsigned char key_val;' {/ k/ g" N/ R( E+ T! q( P
read(fd,&key_val,1);
' Y* b: D: Q9 d$ ] printf("key_val = 0x%x\n",key_val);/ @0 W3 J2 f- u" c5 o* i
}2 `( W D% |+ G% r' k* ^ y1 o
! [5 ^1 n% ~) D0 y# [& p; o
0 b5 ?) Y, e: G I
/* fifth_test# a# i, y- Z4 r, P
*/ / S& b1 F4 Y! K+ z4 O
int main(int argc ,char *argv[])4 p4 |$ x/ D6 U0 k, z5 r8 \" l
{
2 w+ m* j/ d7 U. |9 C9 r int flag;
O0 V$ W- O2 N5 a4 H' ` signal(SIGIO,mysignal_fun);& D% b6 G& x: H3 k. k9 K0 H1 [3 y
5 Q' x. G' F5 n/ j fd = open("/dev/buttons",O_RDWR);* k+ \6 ~$ F! p3 v8 P9 e
if (fd < 0)7 R) k8 ?% p" x- y6 d! |5 ]
{8 [0 F, t2 |! a
printf("open error\n");
/ O( p1 B z n7 b! s4 b" {$ n }
7 U. p6 B! Z9 \9 Q& o- ?$ C9 Y; B3 }9 F! V) ?: w4 N- o
/* F_SETOWN: Set the process ID
+ ^$ H# D; Z/ F * 告诉内核,发给谁
* b! y& K8 Q* r$ [$ x: I( C */
7 U+ V% s- l# b' L, y: S0 r fcntl(fd, F_SETOWN, getpid());
/ X% _. L+ ]6 a/ `! u* y$ N3 D' j* t" ?/ q3 F
/* F_GETFL :Read the file status flags
0 H; }: [1 j; y$ W: p \) \. N * 读出当前文件的状态
, C& E2 F* F2 q; x/ X */% ?. f! d0 R$ }2 `
flag = fcntl(fd,F_GETFL);9 ]. K( H. ~' y( t% j6 D0 l
T* X0 w# g V /* F_SETFL: Set the file status flags to the value specified by arg$ {' \) b. y8 x: s0 Z5 P
* int fcntl(int fd, int cmd, long arg);! u, q/ |" |1 ?$ l' N& M7 V
* 修改当前文件的状态,添加异步通知功能 J/ Y1 }* E1 k# w, u6 p4 y/ }: @
*/6 C1 J$ O; U1 R t/ Q% C+ ]
fcntl(fd,F_SETFL,flag | FASYNC);1 U0 W# @9 _3 p3 B6 O
) f3 ?9 I; V# v) @
while(1), y0 ?' I( M: ?, w* r
{
4 B: w0 d( y( ]4 |% c; v& h! ]5 ` /* 为了测试,主函数里,什么也不做 */+ i0 n( _" M6 u [; N6 k
sleep(1000);
7 X& d6 c+ f; G }
8 t0 L5 w; G D, H# o return 0;" ~' p, e1 p8 [2 O
}6 v+ A q" w \. @" U
7 Y8 }! H0 }1 o3 P6 P' {
测试步骤:' t+ @1 f8 t) d; O+ m# q Z6 ~
/ A; u8 D( _' |[WJ2440]# ls Z. V% E+ i) }; Y
Qt fifth_drv.ko lib sddisk udisk
& X+ |8 Z5 Y5 g# w# @1 A2 ?3 }, WTQLedtest fifth_test linuxrc second_drv.ko usr
. M6 H& B2 p, `* G W* W- ~8 d1 N; gapp_test first_drv.ko mnt second_test var* N$ `8 I7 s8 m2 } d" m; _
bin first_test opt sys web
# R% c- N# D. {! I7 K/ ?" vdev fourth_drv.ko proc third_drv.ko
1 _. v% a. Q8 z% D! _1 fdriver_test fourth_test root third_test+ H% R. f5 u' M E V/ a6 z* p
etc home sbin tmp
7 k2 r M0 c8 V, l- T9 ^! J; ~[WJ2440]# insmod fifth_drv.ko
+ a0 {, C6 G- K- j[WJ2440]# lsmod
4 f E$ `6 Y5 D2 j2 t; ~# R* jfifth_drv 3360 0 - Live 0xbf006000
, c8 l9 [% ?+ H2 X[WJ2440]# ls /dev/buttons -l
6 G- e3 L' Z3 i: y" H6 L* Vcrw-rw---- 1 root root 252, 0 Jan 2 04:27 /dev/buttons
$ e# _# I L1 y[WJ2440]# ./fifth_test : z; O# X4 g* _# m/ y0 U
key_val = 0x1, F; l% P- m3 f8 j, R
key_val = 0x81
" @# N! V2 M& L: M- mkey_val = 0x4
. H8 \' |5 N- m) u* T0 rkey_val = 0x84
1 L( \8 @3 x& K4 ~" gkey_val = 0x22 G& U) r2 i; k: h# m
key_val = 0x82
: l; ^) U$ a; O5 |% Nkey_val = 0x3
5 l$ N2 |- f5 ~3 A1 @7 z5 D" P; ~- \) Rkey_val = 0x83
* `6 a/ \4 H+ |7 A6 B) Skey_val = 0x4
* {* ]- l3 C* y5 _. \) D9 `: A1 o7 o% Skey_val = 0x84
' @/ ]/ J$ {* U4 Vkey_val = 0x84& n, Q& r4 z, t& @
5 x' K$ W+ D& y) b, k由测试可知,当无按键按下时,应用测试程序一直在sleep,当有按键按下时,signal会被调用,最终会调用mysignal_fun,在此函数里read(fd,&key_val,1);会去读出按键值,这样一来,应用程序就相当于不用主动去读数据了,每当驱动里有数据时,就会告诉应用程序有数据了,你该去读数据了,此时read函数才会被调用。) Y1 \! o8 p6 U& i7 c
7 u" N7 x; E" A" \4 ^7 _) x: v3 m4 e' K
这里最后总结一下老师的笔记:
]1 \0 I: i3 J. h5 E4 o3 ?( d+ x" S2 l3 b2 v
为了使设备支持异步通知机制,驱动程序中涉及以下3项工作:7 I2 q: o9 E; V; U/ R
1. 支持F_SETOWN命令,能在这个控制命令处理中设置filp->f_owner为对应进程ID。
8 p* W5 r$ S4 `' ~1 q# i 不过此项工作已由内核完成,设备驱动无须处理。
" u! ?) q R0 g' ?2. 支持F_SETFL命令的处理,每当FASYNC标志改变时,驱动程序中的fasync()函数将得以执行。
3 K6 R( q9 k- D1 U# u* D 驱动中应该实现fasync()函数。
/ I% l- T* k) D0 u3. 在设备资源可获得时,调用kill_fasync()函数激发相应的信号6 G2 C/ y8 C& J4 D' K" t1 s6 Z2 a
G* U6 |: X( T) V' k+ W3 P/ K9 Z应用程序:
' X) p2 q# Y1 b& H& \ \fcntl(fd, F_SETOWN, getpid()); // 告诉内核,发给谁7 J: p' q1 h k/ k5 L& T
6 n+ e+ ?. J1 }, }( ~
Oflags = fcntl(fd, F_GETFL);
: k- y' Q+ }( d) M- [fcntl(fd, F_SETFL, Oflags | FASYNC); // 改变fasync标记,最终会调用到驱动的faync > fasync_helper:初始化/释放fasync_struct
( a9 q# z0 w6 l0 _
% E) R1 T p/ r! N+ z% m& q
' x/ l% P( a8 m- D- n. v$ d6 P7 t# a: W
|
|