|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
在上一节里,我们在中断的基础上添加poll机制来实现有数据的时候就去读,没数据的时候,自己规定一个时间,如果还没有数据,就表示超时时间。在此以前,我们都是让应用程序主动去读,那有没有一种情况,当驱动程序有数据时,主动去告诉应用程序,告诉它,有数据了,你赶紧来读吧。答案当然是有的,这种情况在linux里的专业术语就叫异步通知。
. L% M& ?9 l2 B, l0 d
$ ?( o% l' w, ~上一节文章:* Y$ I# ` I9 D
* R3 U& d. r3 \+ [# a3 ~* g1 H: \
0 Y; ]; q- c0 Y, b+ [, i; u在这一节里,我们将在上一节的基础上修改驱动,将其修改为有异步通知功能的按键驱动,目标:按下按键时,驱动主动去通知应用程序。
; l8 F3 K0 j% o7 @% s, h! Y3 U1 X. d7 v( m3 F- f
问:如何实现异步通知,有哪些要素?. c$ P+ R9 X' ~ e$ b- k
: ^9 e+ F1 O" B8 ]! s, X* s3 Y
答:有四个要素:1 _. B& _! ~ ]9 y7 Q2 i! h+ d
1 a" B2 Q( f8 t7 @8 {& L d一、应用程序要实现有:注册信号处理函数,使用signal函数: K6 ?6 Z& m7 m% Q* a d# Z" }0 _ a
' E9 Z$ X4 C' n" L9 X6 P3 a# N
二、谁来发?驱动来发
6 a* p( S3 U" |1 s* I
4 t- v) E* [/ D3 p, ]* u: K三、发给谁?发给应用程序,但应用程序必须告诉驱动PID
# q9 A: [6 s+ k! k: ?
- z/ f( {/ D1 i& A4 C/ [+ }9 |四、怎么发?驱动程序使用kill_fasync函数
" D, M: p' ^9 o0 K9 L$ E1 |
+ Y8 W9 t9 }7 T; n) L2 P6 p问:应该在驱动的哪里调用kill_fasync函数?# E! k- _2 F9 b" b- _# t# ], r' N8 H
; Q/ Q: V- [# n5 C2 _! u$ q答:kill_fasync函数的作用是,当有数据时去通知应用程序,理所当然的应该在用户终端处理函数里调用。9 ]( r( _! n, E; k: H8 `
; T# M2 G4 \; W. D问:file_operations需要添加什么函数指针成员吗?
% ^9 u" H) D# Q1 d$ R; J
1 W$ M( M7 c+ o2 p3 P% N答:要的,需要添加fasync函数指针,要实现这个函数指针,幸运的是,这个函数仅仅调用了fasync_helper函数,而且这个函数是内核帮我们实现好了,驱动工程师不用修改,fasync_helper函数的作用是初始化/释放fasync_struct
- q7 H& a# v8 c c9 i/ q2 T4 V0 D6 P2 j
I6 P) c: ^ _, Y# I5 D: t/ ?
( r) d5 i& p3 X" W" Q% [0 X6 ?详细请参考驱动源码:
5 [' s5 L7 q- Q6 R$ {" b6 R$ N* n2 w; j. J D- b% g
3 y, h) Z# x0 W- @" Z: ]8 d
#include <linux/kernel.h>
8 A* ]2 e$ Z" L; p) T2 b# I6 Z/ l#include <linux/fs.h>- r$ x# A; B s" K7 c9 C; T2 w. M
#include <linux/init.h>! \- K! H7 M, q% v9 D
#include <linux/delay.h>
8 Q: `! X+ k5 E: T# N7 {$ i#include <linux/irq.h>$ ?% X- o. ^ v- h4 `
#include <asm/uaccess.h>' v, v- w/ Q3 B8 L( g6 ^- t
#include <asm/irq.h>8 j! B$ j- l9 q5 q9 o' p
#include <asm/io.h>
: w* b- _- u: ^) k3 a, G#include <linux/module.h>$ _3 a4 W4 y' j5 B* u! Y1 T
#include <linux/device.h> //class_create9 H3 d3 n+ N, C! P
#include <mach/regs-gpio.h> //S3C2410_GPF1: p7 }1 o, T* \( L2 }) h; E
//#include <asm/arch/regs-gpio.h> " s, M! W, O$ Z; ~, G6 S# A
#include <mach/hardware.h>
! [% i' o! d: |* P; A) F//#include <asm/hardware.h>
7 Z0 v2 K, t* v0 X! O3 \8 J#include <linux/interrupt.h> //wait_event_interruptible
: p+ _7 @+ b# K0 H3 H#include <linux/poll.h> //poll3 H0 o3 ]% J& n2 |% d
#include <linux/fcntl.h>3 {' e+ ]3 ?8 p I2 Y( `! K
* P6 Q9 D+ d" V3 E N4 j& O
, ?! d( z' I) T% [
/* 定义并初始化等待队列头 */3 ^. j1 T& c' \* Y9 h/ B1 `0 j
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);( Z0 p! r r/ t! L v- _: y ?' \
& r4 w# p Q4 |$ F
# X: x1 l8 r( T; Y
static struct class *fifthdrv_class;; h1 k/ Y# L7 ?; K6 [
static struct device *fifthdrv_device;4 d2 K2 k# s6 O+ |0 z% |
p/ [0 c0 i/ n ?5 H& g5 `
static struct pin_desc{
1 c" a/ O* s I. b$ k! Q unsigned int pin;
: h' G: E- u, ]; H# |8 n, G( O unsigned int key_val;
$ n3 I' J* x7 f: B8 R! h};( s$ _+ A) H5 K( ?3 n
# r; s- o1 r Kstatic struct pin_desc pins_desc[4] = {
+ {6 x* H# Y8 H' i# ~0 ? {S3C2410_GPF1,0x01},
3 [, p! G- B h6 e+ e {S3C2410_GPF4,0x02},
( m- h; z8 Y8 r {S3C2410_GPF2,0x03},! B4 l+ o9 k; i& S
{S3C2410_GPF0,0x04},
- {4 |8 a+ k4 n0 e+ z};
1 K+ ?. Z# K8 q) e* [5 `4 Q5 L* e3 l' s! V$ q$ A
static int ev_press = 0;* G3 c+ Z5 A- q
. I, Z" \3 t( J0 f
/* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */
5 M5 R: t1 \' h+ {/* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */' H6 t7 D5 t( Y! g
static unsigned char key_val;4 D* p3 y- t% j- } Z0 W
int major;, k7 S8 u) P- f, v4 |2 K- e
0 n G& `$ X/ H$ ostatic struct fasync_struct *button_fasync;9 f1 z4 ?2 m2 P
" E1 k3 T* r; j) _/ N6 K/ o4 s/* 用户中断处理函数 */
% w! ]5 h t D' _4 ]4 M: Fstatic irqreturn_t buttons_irq(int irq, void *dev_id)9 R1 n& g6 L% G, b5 a6 B; a+ s
{
Y0 C8 X. l! T5 d struct pin_desc *pindesc = (struct pin_desc *)dev_id;
j d" C2 X6 }4 W3 `; i$ b, P0 z# _ unsigned int pinval;6 F5 z5 k9 d2 C! h0 ]8 C9 X
pinval = s3c2410_gpio_getpin(pindesc->pin);7 U$ T% U' D0 m! E7 v" A: G2 G
2 S& P, Z; ~ k* A% C& s& M6 S if(pinval)1 a$ k0 W, A( F0 _: e
{8 D U$ y8 T" X0 G+ U
/* 松开 */
: H! h9 O* T: }$ ~; l3 v6 c: ` key_val = 0x80 | (pindesc->key_val);0 d# n5 {5 B& ^$ s6 m7 n
}3 G+ u1 }' d6 }; }1 A ^/ r9 W/ d
else
5 }8 c6 `6 W& J' b& L4 a1 S {6 ]$ j, U3 K, j' x/ N5 X
/* 按下 */
/ E6 ~. |! ?) f5 [3 V- ~( ? key_val = pindesc->key_val;1 r9 W: w! t' l' A' M
}: o2 L! a% z7 E& g& P: j
" p/ `, U% S4 Y' f1 f
ev_press = 1; /* 表示中断已经发生 */
8 n3 [* t" j9 A' N wake_up_interruptible(&button_waitq); /* 唤醒休眠的进程 */
9 w, [1 [! c* {
8 Z/ O$ o3 @' @/ @4 x9 e1 q: F /* 用kill_fasync函数告诉应用程序,有数据可读了
9 P& @2 f; l* i" o * button_fasync结构体里包含了发给谁(PID指定)" ^, L1 S+ f5 g9 S# Y* |' |- q9 a
* SIGIO表示要发送的信号类型. |9 R0 ]1 M6 x" e% }1 Y* |/ z: U
* POLL_IN表示发送的原因(有数据可读了)* p: M! R8 B$ ^
*/
) R- D+ L. I& a1 L kill_fasync(&button_fasync, SIGIO, POLL_IN);
, {" K3 c; W- S$ T$ }) x. R return IRQ_HANDLED;; o4 {& P- y( P7 P$ f2 P2 a2 O& g
}
1 q' O% C, [0 L; p. rstatic int fifth_drv_open(struct inode * inode, struct file * filp)
* }5 I8 N& D4 x( [/ Z9 |{
4 u/ H U) b/ L: H9 I /* K1 ---- EINT1,K2 ---- EINT4,K3 ---- EINT2,K4 ---- EINT0* p" k7 `5 o* s" o/ N
* 配置GPF1、GPF4、GPF2、GPF0为相应的外部中断引脚0 B6 O P; S+ H
* IRQT_BOTHEDGE应该改为IRQ_TYPE_EDGE_BOTH
2 ^3 K" ?& w+ B; ? */
. h4 `4 w; n2 [. U2 w7 ` request_irq(IRQ_EINT1, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K1",&pins_desc[0]);
2 Q. {: p4 m+ c request_irq(IRQ_EINT4, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K2",&pins_desc[1]);, b7 Y, J% s- @5 n. ` D6 Z* d
request_irq(IRQ_EINT2, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K3",&pins_desc[2]);" o5 w+ R. K1 l' W
request_irq(IRQ_EINT0, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K4",&pins_desc[3]);
1 g) n' r, N! D3 _# _) ~ return 0;
9 K% {" l0 H! c8 {0 w( v}6 _* _( M. X3 ]) m
$ m4 n% ^( h/ _
static ssize_t fifth_drv_read(struct file *file, char __user *user, size_t size,loff_t *ppos)2 N9 G: l0 g3 `
{7 o8 ^; d/ K6 V$ _2 v
if (size != 1)
1 {+ ~, _" z& `5 u9 z; Y, T return -EINVAL;2 _ q6 b* y$ q8 [
4 v0 Q2 {) H/ z1 Q# I. ?/ v$ i& E
/* 当没有按键按下时,休眠。
8 I% h$ H" k& s * 即ev_press = 0;
9 b5 r) T+ ?! @4 } * 当有按键按下时,发生中断,在中断处理函数会唤醒6 I) b( i2 x( X$ q. A3 d# Q
* 即ev_press = 1;
1 I X' ? [- b8 @; g* Y- O% D* A9 b * 唤醒后,接着继续将数据通过copy_to_user函数传递给应用程序: r/ b+ I+ ~1 \7 r) r6 L" v
*/
' L. `; V/ z+ s4 u wait_event_interruptible(button_waitq, ev_press);# _2 ]) a1 v9 \/ _/ g6 d
copy_to_user(user, &key_val, 1);: }+ ]3 U, w r% X+ \' D
% a/ F# l3 N3 a% t# ^$ x3 ?
/* 将ev_press清零 */
" \* V! h l h* b* a ev_press = 0;
; M0 [7 c# h$ }5 ^! P( y return 1; 4 M$ j# V q: p8 N; w
}, U U% L9 @7 S2 ? O* M2 P% ?
& N8 _! R! y$ a o- i9 V
static int fifth_drv_close(struct inode *inode, struct file *file)
$ f) f- I9 E# [{
" k) d' g$ y1 S% t free_irq(IRQ_EINT1,&pins_desc[0]);! ~ `7 R8 c1 N q7 ]' N' C1 X9 @
free_irq(IRQ_EINT4,&pins_desc[1]);3 S( O* _+ s7 f8 G( G) V
free_irq(IRQ_EINT2,&pins_desc[2]);: _ p0 u# U* V5 R$ m$ A0 \4 e
free_irq(IRQ_EINT0,&pins_desc[3]);
$ q$ x2 m& x3 U" L, Y1 ? return 0;
6 _6 ]5 r1 \+ g, k+ G}6 Z$ Q; q0 _1 W) I
# o. I5 m) I' r+ ]/ bstatic unsigned int fifth_drv_poll(struct file *file, poll_table *wait)" G8 @) C! m$ H7 T: b0 k; M( Y
{
0 ?/ V( F( j! y; k" z7 J5 n unsigned int mask = 0;
6 l- _* t0 z& s. [4 Q9 q8 {' A l1 m; \* w1 B* A% Q* i
/* 该函数,只是将进程挂在button_waitq队列上,而不是立即休眠 */* y' I' I' `. i9 O9 E# p2 x9 _
poll_wait(file, &button_waitq, wait);
2 I) x- K k' }5 g. P6 V6 J0 R3 x7 S) r) o" ?( H: P. F2 n
/* 当没有按键按下时,即不会进入按键中断处理函数,此时ev_press = 0
/ I M3 _3 z' y5 B+ \ G8 x# @ * 当按键按下时,就会进入按键中断处理函数,此时ev_press被设置为1. Z. J; i1 k! v7 V) X3 W
*/
1 s) k1 G4 |/ d- P if(ev_press)
3 E2 y1 I+ K% r+ v, z/ l {
& }3 \9 s* f- W% B* ]4 P% j mask |= POLLIN | POLLRDNORM; /* 表示有数据可读 */
4 C6 m! o: t& E+ ?2 T8 g0 p; }, I4 A1 A }
" e2 Z: Y6 S8 Y9 F& _/ z' ^% D" D3 S: u1 p v
/* 如果有按键按下时,mask |= POLLIN | POLLRDNORM,否则mask = 0 */$ _1 b/ Q& U) ~& R) h& K8 b
return mask; 7 j- O6 N. w; d2 }
}0 @, t6 k# k9 j+ {
/ b( }7 [5 a; S. }& U7 d/ L/* 当应用程序调用了fcntl(fd, F_SETFL, Oflags | FASYNC); 5 c! H9 Q+ v( G8 L) ^) W3 Q
* 则最终会调用驱动的fasync函数,在这里则是fifth_drv_fasync, q6 o2 V! `0 q' f2 N# U, c8 l) Z. n
* fifth_drv_fasync最终又会调用到驱动的fasync_helper函数
4 |& R, w% i+ P' g1 N2 A * fasync_helper函数的作用是初始化/释放fasync_struct
# b* l% C0 k) U0 O8 p */
; r1 g& E+ O- O8 @7 W+ S. gstatic int fifth_drv_fasync(int fd, struct file *filp, int on)
+ z! N; m2 `. Y6 r4 ^0 \* `{! U* D* V. c2 O) v5 j
return fasync_helper(fd, filp, on, &button_fasync);" L: K1 I$ {$ m9 A$ y; c' F
}$ S5 a& ^; ^: O+ K; M
! [- a+ @3 } O" G' K* ?/* File operations struct for character device */( L& H# @( v& D2 n w; _
static const struct file_operations fifth_drv_fops = {
- O: u- [0 L2 Z .owner = THIS_MODULE,
/ f# V( f2 O9 a1 @9 d( S: ` .open = fifth_drv_open,% b6 S3 c9 F: g0 B1 l, l. ]7 k
.read = fifth_drv_read,5 j) ]. Z5 L( J9 W* B
.release = fifth_drv_close,' {7 u# ]9 w% M/ P* c
.poll = fifth_drv_poll,
/ m2 g, E* n# s/ j6 u; Y .fasync = fifth_drv_fasync,
- v/ r( l; g% Q/ ?" ]+ k};6 W" G J4 x8 W; _. v0 }7 B
( d4 c0 [" k* E0 h" m& t
& F" \) L: e; @! |
/* 驱动入口函数 */
z, W7 N( S E3 S( x6 P4 \static int fifth_drv_init(void)
/ D( u$ N0 ~. t- k- u0 Y) H{3 L% w$ q: e; F9 x% M+ ]6 T' h
/* 主设备号设置为0表示由系统自动分配主设备号 */$ ?: [' ]8 d; W3 E+ U
major = register_chrdev(0, "fifth_drv", &fifth_drv_fops);
, `/ Y2 B( a* p$ W- D
) H7 W" }% n8 i) L6 x" l /* 创建fifthdrv类 */
3 ]) M9 m( h) _- M2 H' d; W: u fifthdrv_class = class_create(THIS_MODULE, "fifthdrv");
+ J: U: S: {, F! Z9 y0 X; J
# B3 N4 U" u: J% k7 R /* 在fifthdrv类下创建buttons设备,供应用程序打开设备*/6 k+ G. O" {4 M0 `! J3 j6 S! i% z) k
fifthdrv_device = device_create(fifthdrv_class, NULL, MKDEV(major, 0), NULL, "buttons");
* O+ m% g3 }5 k j3 R' I Q2 M1 c: A* s7 ?$ x. A \3 x
return 0;
9 X- @/ \- ~* |}; G9 ?9 @# n# b" y5 B, y5 o# D3 e
7 F, z7 `( j" @# [# ?
/* 驱动出口函数 */$ }; r. J A% e/ X/ y) ~
static void fifth_drv_exit(void)
% T( O0 A! }# x: s{" z r' `- ?& P4 ~; A
unregister_chrdev(major, "fifth_drv");) H# k# W% P8 N" }) z8 o8 _) M2 C& o
device_unregister(fifthdrv_device); //卸载类下的设备" a8 x3 F. m7 | S# C/ `6 d; e
class_destroy(fifthdrv_class); //卸载类
$ w! {3 \" b0 o5 ^& g7 U}
1 M, c3 c4 F% M9 d& K1 {9 H% {% ?6 Y e% M \' h& w' v2 M
module_init(fifth_drv_init); //用于修饰入口函数, J% |9 R2 s% y0 L8 j4 E: T8 C+ G
module_exit(fifth_drv_exit); //用于修饰出口函数 ; j' O5 k2 M, t$ K
0 l' M# |" L3 J6 K
MODULE_AUTHOR("LWJ");
) D4 u8 j- d* H+ ?3 cMODULE_DESCRIPTION("Just for Demon");
! l2 d B7 W2 V9 H% P& | {MODULE_LICENSE("GPL"); //遵循GPL协议& y+ l3 P' s$ Y( U- A
& E! i. j1 u( N+ K: v5 c, @0 h- X应用测试程序源码:
# o9 v$ }! d2 c$ Y" I4 p$ H
8 v5 G' O" h, w! c2 S#include <stdio.h>
9 w, [! V0 ]- R* N) W#include <sys/types.h>
+ M6 E! c I- ~$ D#include <sys/stat.h>
& A$ w" N/ ^- N3 p* I2 C#include <fcntl.h>
- }. E* N5 u4 ~* U- X# j6 [#include <unistd.h> //sleep
, T: o( q. x6 c9 P& j: w#include <poll.h>5 d) c9 a. z$ x% {& @0 m, v
#include <signal.h>
8 V4 \& I% l$ i* N, k: }# B#include <fcntl.h>+ l$ D' H5 O# a) J% [% l) w( R
: j2 T) {- C# ]5 ~" @int fd;
% G2 G) Q: [( U0 P/ u
6 e) k/ z! n7 F% ?' _/ ivoid mysignal_fun(int signum)8 K% I% t c% f
{" a( N- x% ]' u7 \
unsigned char key_val;
& O& L" }( M+ q7 W! W+ O g4 v read(fd,&key_val,1);
: w0 u f0 W5 f1 J7 t# t printf("key_val = 0x%x\n",key_val);
. ]- C+ B3 X* n5 I) {5 M}
# M, B( s% H# V, `8 _
& r' B8 C. p" I" e: \7 |9 o, n/ a% S. K
/* fifth_test/ ^9 W6 g, ^' X' f" H
*/
- [6 F k' y/ a, a/ z0 D9 }( D \int main(int argc ,char *argv[])7 G; P9 v* R3 Z8 C
{1 }! @. k& v, P
int flag;( R! b, U- ~/ }3 K; j% l( \- o6 x
signal(SIGIO,mysignal_fun);- E4 e' [( Z0 j* I2 G
8 t K! u0 I# {% b' [: j
fd = open("/dev/buttons",O_RDWR);8 F: R+ r- d2 L# ^ s
if (fd < 0)
( s" y# [2 z) v4 X/ u0 \ {
" g2 {" h$ K2 K! O7 V/ I* P printf("open error\n");
2 m* r% {0 o8 R( Q9 |/ { }) R2 x9 ]4 k1 o$ l
( K/ p% e u8 s7 A7 f
/* F_SETOWN: Set the process ID2 C* y$ F5 p: \3 m4 w
* 告诉内核,发给谁
% I! W9 O+ I& u& R/ A */, x7 r( F, ~$ m) L% C7 ~" B
fcntl(fd, F_SETOWN, getpid());
' L: q& Y2 Y8 x! r
0 z+ c# Z5 ? T# P8 ~1 P& D /* F_GETFL :Read the file status flags3 D& C6 J8 F! H8 |8 i
* 读出当前文件的状态
' h f6 Y |2 C! a, X3 O */
5 j* X3 n1 @) Q& w: c% f& H flag = fcntl(fd,F_GETFL);
2 V, M' J# k: t% y( Q+ U( y1 L3 }
8 N+ D3 o% B: C, g8 @! ] /* F_SETFL: Set the file status flags to the value specified by arg
k0 [& h7 M( _* O0 |' I1 G7 S * int fcntl(int fd, int cmd, long arg); S) d7 G% W% B4 V; Z3 r- y k- Q
* 修改当前文件的状态,添加异步通知功能
) y( j) w7 F1 x. F( D */3 `4 f/ d6 U: u3 U; a
fcntl(fd,F_SETFL,flag | FASYNC);; y+ n x+ t5 M+ o+ F" ]: X( |
4 P4 w+ \( ]' w
while(1)8 c j% E& a0 i# @ K
{/ g( A0 p$ L8 E: f* q
/* 为了测试,主函数里,什么也不做 */1 x, K4 |: X; {
sleep(1000);
+ L, P. w! d1 ?/ e! A3 l }# k8 {; }% N2 P a
return 0;' ~8 u1 z; I0 Q, P3 r1 b
}
" d5 Y3 }4 p3 h* W+ d, Y9 s2 {9 D! W$ {/ C: Q/ l6 ~8 l5 ?
测试步骤:
/ N1 ?3 R: Q" V+ x% k/ T* M% ?, D+ C2 ?! ?7 _, q
[WJ2440]# ls 8 O% n& a& G4 c8 E) ]' [- t2 ?
Qt fifth_drv.ko lib sddisk udisk
6 s# \* s, i* W% FTQLedtest fifth_test linuxrc second_drv.ko usr5 c9 z* {( t' V0 y' C- l
app_test first_drv.ko mnt second_test var; O" y: T( R5 u( b
bin first_test opt sys web
* I0 h& ~9 A B4 Qdev fourth_drv.ko proc third_drv.ko
( S% o: t- c1 g! k8 Jdriver_test fourth_test root third_test3 g2 @& ^( c# u6 F- q# H# u
etc home sbin tmp. x$ c9 v3 k" K; }
[WJ2440]# insmod fifth_drv.ko
, k3 T8 Q m: A! E% I6 R[WJ2440]# lsmod' `( g6 `3 \, }* v1 ^% t9 j2 ~( ]
fifth_drv 3360 0 - Live 0xbf006000
/ J- V. y& e/ w8 @1 T1 H[WJ2440]# ls /dev/buttons -l
4 y A# Y" [8 a1 u" C: T: {' ucrw-rw---- 1 root root 252, 0 Jan 2 04:27 /dev/buttons" I E, K2 c, a. w5 _3 A
[WJ2440]# ./fifth_test " D4 l9 O8 q8 h) C0 j0 _6 L
key_val = 0x10 {/ U- G8 O* D8 ]1 ~2 L6 m0 E X
key_val = 0x81
7 z2 U* J/ f7 m' O6 Rkey_val = 0x4
. h6 G/ o0 t( J! K7 ^" ekey_val = 0x84
t6 `; K A1 x4 z1 Hkey_val = 0x2
# ]0 R0 i! U$ x" xkey_val = 0x82+ y w* S" O& n2 W6 Q6 j% K
key_val = 0x3# b0 }6 p3 t( K& r, S$ f
key_val = 0x83
. v9 m4 Q$ b3 u. _+ x: ykey_val = 0x48 d* S7 `: p' M3 p& D
key_val = 0x84
/ k* w8 @! V) y3 Z4 c3 ikey_val = 0x84
& v& v" w: O5 N$ n3 I( o
( \; S ~( ~9 h( V由测试可知,当无按键按下时,应用测试程序一直在sleep,当有按键按下时,signal会被调用,最终会调用mysignal_fun,在此函数里read(fd,&key_val,1);会去读出按键值,这样一来,应用程序就相当于不用主动去读数据了,每当驱动里有数据时,就会告诉应用程序有数据了,你该去读数据了,此时read函数才会被调用。2 v( H# f% f, _: o3 |6 x
( q) J- ?9 X' a3 O" `5 k4 B/ S5 N, ~/ u; V( q- r$ L$ n
这里最后总结一下老师的笔记:/ w& h/ ^+ p6 I
' K! q2 z7 V( F- w7 X# D# W) X
为了使设备支持异步通知机制,驱动程序中涉及以下3项工作:
: U8 i: I' B0 \* V# i2 c; ^" _1. 支持F_SETOWN命令,能在这个控制命令处理中设置filp->f_owner为对应进程ID。
, h1 l; V9 s H; P+ M$ b% { 不过此项工作已由内核完成,设备驱动无须处理。. g) I- K9 r1 F+ h7 L
2. 支持F_SETFL命令的处理,每当FASYNC标志改变时,驱动程序中的fasync()函数将得以执行。
C, V4 g9 ~* l$ p 驱动中应该实现fasync()函数。1 T% F% u9 _' f T% E+ _! k" l# d
3. 在设备资源可获得时,调用kill_fasync()函数激发相应的信号' F0 k% G9 i% s* ]
( R) l, l2 M. t2 c" k应用程序:
& D# C% y2 U9 v ifcntl(fd, F_SETOWN, getpid()); // 告诉内核,发给谁7 B; [4 A1 `$ N8 a6 D: H
/ v0 u; c7 ?/ r) C! H. A6 p" J! ?: xOflags = fcntl(fd, F_GETFL); 8 D, j# b! N" s# |5 z$ Z# \* }) Q
fcntl(fd, F_SETFL, Oflags | FASYNC); // 改变fasync标记,最终会调用到驱动的faync > fasync_helper:初始化/释放fasync_struct
- d/ u5 ?- t8 E% o3 I2 |' s0 P8 Y8 c8 y9 Y% t
1 r' T1 k* |6 E2 g( C% Y0 M% z) l. J& ^
|
|