|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
在上一节里,我们在中断的基础上添加poll机制来实现有数据的时候就去读,没数据的时候,自己规定一个时间,如果还没有数据,就表示超时时间。在此以前,我们都是让应用程序主动去读,那有没有一种情况,当驱动程序有数据时,主动去告诉应用程序,告诉它,有数据了,你赶紧来读吧。答案当然是有的,这种情况在linux里的专业术语就叫异步通知。* b- M% y# k. Y
4 B2 l- M* Y) Q! x" O- P6 U上一节文章:7 ~3 f% ?$ n0 |) M
8 Z) ~* r: d, r( p6 b6 V
% E, L$ r3 A9 \" N; D9 R7 u- |在这一节里,我们将在上一节的基础上修改驱动,将其修改为有异步通知功能的按键驱动,目标:按下按键时,驱动主动去通知应用程序。
% u, o6 U3 V# G# t0 J
1 ^( @& t9 K% X4 |9 e* r问:如何实现异步通知,有哪些要素?; S& t* a! J4 o6 {+ a. B( f0 |
! B b# f+ v) q! F5 `( j6 u; @/ y: n/ {
答:有四个要素:8 @& M( U/ @7 N$ v: ^& b
4 ]8 C" \6 U, ]; f
一、应用程序要实现有:注册信号处理函数,使用signal函数* w' D( w- J% W. Z, m( H* M
: }5 O. y7 {' T# B" R
二、谁来发?驱动来发
u$ I3 y: |& C, W& q) t, Q
4 F9 d* J9 |% V! i三、发给谁?发给应用程序,但应用程序必须告诉驱动PID
$ L. `% C3 z x- C2 S4 j! j0 D0 d& D9 W E1 b% T* O
四、怎么发?驱动程序使用kill_fasync函数6 ]: x4 u( `- e/ F( U
2 O# @) u' c" S! f问:应该在驱动的哪里调用kill_fasync函数?
8 L, V* v7 g" f% r; a N4 k
% `( l5 Q* b- O6 L0 U1 [1 h7 c答:kill_fasync函数的作用是,当有数据时去通知应用程序,理所当然的应该在用户终端处理函数里调用。+ c. W0 Z' c& j1 F0 x
4 }7 n9 ~! r V- R% t, E: c问:file_operations需要添加什么函数指针成员吗?) X/ B2 `1 F6 K* I7 l0 N' X
; L( t! Z* X) B" W答:要的,需要添加fasync函数指针,要实现这个函数指针,幸运的是,这个函数仅仅调用了fasync_helper函数,而且这个函数是内核帮我们实现好了,驱动工程师不用修改,fasync_helper函数的作用是初始化/释放fasync_struct
! P% ]: G, E" G" l* [ Q# j9 P; v+ Y* X8 R$ d C( D1 u9 ?( l
$ D+ e6 q/ D. X( A f" |) b
0 b: v. k5 i3 {$ q$ G! U
详细请参考驱动源码:
& ]1 U! F. c; ~, Y9 q/ c5 M' c6 G* G0 ?6 Z1 }0 K
) G. E3 \3 A+ L% w9 c#include <linux/kernel.h>$ K' R1 _- p) n1 E( S; D* Z5 B8 y( E+ g* O
#include <linux/fs.h>
: g$ ^+ q# s- j8 [! z! f+ b7 O#include <linux/init.h>0 u1 X& w5 K1 t+ s" f' x
#include <linux/delay.h>
0 O8 a& a7 S( c* j' W+ Y#include <linux/irq.h>1 l% U& s, I9 N x- L
#include <asm/uaccess.h>
% @! ^ N t. ^% @( q#include <asm/irq.h>. _" d# [: A; `6 c1 B7 ?
#include <asm/io.h>0 x3 H) F9 u S; Z
#include <linux/module.h>6 i) }2 _2 C" } W1 I7 Y
#include <linux/device.h> //class_create) ?' B# o6 B) r& ?! \, g
#include <mach/regs-gpio.h> //S3C2410_GPF1
0 k s' b0 T$ y! j! j Y- S _! Z" W0 `//#include <asm/arch/regs-gpio.h> , z7 s1 _ f5 p: d# J) [8 Y: q
#include <mach/hardware.h>
3 I |6 T/ |. I7 N//#include <asm/hardware.h>3 _( H% S& ^6 U& E' l
#include <linux/interrupt.h> //wait_event_interruptible
3 D! G0 G, P3 W5 R( |2 x#include <linux/poll.h> //poll# ~. D; B1 ? i' e5 g
#include <linux/fcntl.h>
3 R$ R; l2 d& ^) N% }) p y6 `$ S2 a9 ~/ z
; s3 U& @1 K- r" ~* D
/* 定义并初始化等待队列头 */3 K" c3 k E( N/ ^$ h, ?+ m* y( F
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
" D( @1 H, N9 a5 Y |
4 p4 x- l @) Y6 v& a! ~$ I0 t$ z9 z R0 [; Z0 z; c1 H5 ^
static struct class *fifthdrv_class;3 i" ^( i+ s" Y* R$ X
static struct device *fifthdrv_device;
3 g2 G& ], A( Z+ k- a; ?% s0 u) t Z5 W( o
static struct pin_desc{
! I8 O8 c1 [' J) X% H; ^ unsigned int pin;* n$ J$ K1 W4 M) o5 m- d
unsigned int key_val;
/ E# a+ q( Q. t! n8 U. F};+ `6 G$ g n7 @
% A& t( _, E- C$ J! G
static struct pin_desc pins_desc[4] = {
# _# f( p' Y$ s {S3C2410_GPF1,0x01},
. {& T6 b5 K: h) \) G {S3C2410_GPF4,0x02},$ y! F; d+ ?! B# t
{S3C2410_GPF2,0x03},
) U: n3 B2 x7 ]- m& E {S3C2410_GPF0,0x04},
+ Y: R8 V7 Y! K$ O. R- X$ B7 T}; 5 l% _2 [& p% n
' ~! P- z8 X. Y: Y
static int ev_press = 0;( M# Q! g2 {7 b4 n8 P2 L/ R6 X
! r1 x G; G3 E' h8 S! ] y
/* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */, I3 n2 w* C" u- B0 G
/* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */$ U& @* m+ }9 {9 G9 A& `( u) I
static unsigned char key_val;
/ m( i% C+ g' e+ m6 [int major;( o# P* a& u' I3 |$ [/ J- `
1 C1 q% |+ C8 @5 O' E \static struct fasync_struct *button_fasync;
6 e3 L9 z- D) z8 L7 ~- h P7 d' f; m% a; ? N4 b: x! F
/* 用户中断处理函数 */4 e& O2 }. \ M2 Z% Q: e( ]
static irqreturn_t buttons_irq(int irq, void *dev_id)
) V9 u: p# N7 q: Q r2 F% x+ ]{) y0 w1 b; }- K& u' {$ ^
struct pin_desc *pindesc = (struct pin_desc *)dev_id;
9 r) Y/ O* E6 V: f: z unsigned int pinval;
, T0 ] [ B4 e3 r8 m pinval = s3c2410_gpio_getpin(pindesc->pin);
! H, I1 [. R: R% ?. F" n! m( A2 ?* V6 h( M1 f
if(pinval)
* B9 E. q" b, K) q {
, @7 T; Y+ p5 A# J, o /* 松开 */
. N# Y" s, p/ p- s$ [ key_val = 0x80 | (pindesc->key_val);+ i$ D0 u/ \# V5 @5 M/ D, J* ?( A& `
}! Q- x3 D J& J, O9 e1 T
else
3 F7 r6 m, s z0 h; C! S# g6 z {
) Q4 ^3 L; \9 S6 \, L /* 按下 */- [5 m9 L3 q* q/ H0 h* I( H. X: X
key_val = pindesc->key_val;% R# _; M- X' Z* Q2 W
}
* {" W7 L1 H! d5 }, t
. S7 P& G1 ^! e4 Y2 M4 ] ev_press = 1; /* 表示中断已经发生 */; h5 R: @8 o2 M4 _4 q# O
wake_up_interruptible(&button_waitq); /* 唤醒休眠的进程 */
6 q- {7 i. G7 C- x, a8 E3 s- @0 f( s* {1 M3 N$ F+ J
/* 用kill_fasync函数告诉应用程序,有数据可读了
3 @( C7 T# a% I# ^: S- | * button_fasync结构体里包含了发给谁(PID指定)( O' N3 a9 l; h. f6 j5 p3 ?
* SIGIO表示要发送的信号类型
! N9 j3 W" E0 u9 J' g5 s- N" a M7 [ * POLL_IN表示发送的原因(有数据可读了)
7 z6 E4 S0 }. P/ D2 b */& I* r7 O. L& Z8 [# S
kill_fasync(&button_fasync, SIGIO, POLL_IN);
9 S9 m6 H9 @5 g. x0 g3 N, J return IRQ_HANDLED;
6 e8 m; s5 i& W& T}: L+ D9 A; S) ~( T, V3 n
static int fifth_drv_open(struct inode * inode, struct file * filp)
5 U; h) ~6 V% b{
; X+ N( _$ {$ G/ C9 T /* K1 ---- EINT1,K2 ---- EINT4,K3 ---- EINT2,K4 ---- EINT09 E" _6 A6 W$ Y" r: H
* 配置GPF1、GPF4、GPF2、GPF0为相应的外部中断引脚
, u# D% K' q+ n# w6 b" B3 L! E * IRQT_BOTHEDGE应该改为IRQ_TYPE_EDGE_BOTH v. T( i, T3 a# U
*/& g9 s. l; i$ Z; Z) d' k
request_irq(IRQ_EINT1, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K1",&pins_desc[0]);
8 k4 I6 x$ e) t: I+ |/ P8 l$ l0 g request_irq(IRQ_EINT4, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K2",&pins_desc[1]);
8 W" z1 I8 M' D5 L# k$ u request_irq(IRQ_EINT2, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K3",&pins_desc[2]);
9 B% A% _2 l8 v4 {9 Z request_irq(IRQ_EINT0, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K4",&pins_desc[3]);2 \+ q! W; u& W2 k7 a
return 0;; \$ U% D( L7 n5 d, c. j& j
}' S5 a, e5 P" Y; w
% t0 O; e) [+ n+ ~# J& L
static ssize_t fifth_drv_read(struct file *file, char __user *user, size_t size,loff_t *ppos)
6 e9 G9 D0 d7 @5 M `{( U% K% I2 V8 b% j9 l& f, g' S
if (size != 1)
6 t. [# N' S7 a0 c3 k4 I return -EINVAL;5 j, [* k# O" L. e4 f
8 U1 B( O! `2 ]0 P' y /* 当没有按键按下时,休眠。
% ?9 `! U0 m6 S' m! ]9 K& H6 T * 即ev_press = 0;* K6 w) [& }/ {$ w2 d
* 当有按键按下时,发生中断,在中断处理函数会唤醒
6 o- I+ b8 e- V- i1 k) _2 D6 X' @7 s * 即ev_press = 1;
9 @' A3 b1 ~; E5 X$ a; K * 唤醒后,接着继续将数据通过copy_to_user函数传递给应用程序
+ U7 S, t1 _- W! l" Z; X */
+ X' e, H5 s @, {4 j wait_event_interruptible(button_waitq, ev_press);/ h7 S: n Y7 {( }# m4 W
copy_to_user(user, &key_val, 1);
% H8 v' ~% W& }$ N! z7 {! d6 l ( R3 I. D& {- i& t7 B
/* 将ev_press清零 */5 a! Y5 u5 `; J* p8 y2 e% c
ev_press = 0;
- l S; g3 M! l5 ~) _2 j4 ^ return 1;
7 z' x" R. c, l _: a}& G# A. h3 H3 N. \7 v0 w
8 k. s- s) f: e, Q: \" u- I
static int fifth_drv_close(struct inode *inode, struct file *file)8 e4 F6 |$ Z9 |* `
{0 a8 D6 D; q+ ^" b6 X& H
free_irq(IRQ_EINT1,&pins_desc[0]);, m, [* e1 x( `: s9 g3 S
free_irq(IRQ_EINT4,&pins_desc[1]);
$ F: i+ Y7 j; w2 d& b5 T free_irq(IRQ_EINT2,&pins_desc[2]);
9 D; M+ B8 \, S2 F |# d! e; i, B free_irq(IRQ_EINT0,&pins_desc[3]);5 {- D' f2 b; k% P$ G
return 0;: ]( e4 ?6 b% u
}/ O! P. ?( I" m2 v D6 s/ N
$ d1 F' G; A# x( P, k2 }* ?- I4 y' vstatic unsigned int fifth_drv_poll(struct file *file, poll_table *wait)
: s w# _* ?) S+ S# T/ O0 X{; ?2 F* E$ q! \) L/ R
unsigned int mask = 0;, p! B- e5 M8 s4 Z+ x. O
* {7 K, g. d6 v2 k$ b /* 该函数,只是将进程挂在button_waitq队列上,而不是立即休眠 */
% ~8 l+ K3 [- j0 z/ ` @( { poll_wait(file, &button_waitq, wait);
, H, P) c3 x3 `* Z, O" [
% Z* ?/ e0 n1 Z8 C8 A) d /* 当没有按键按下时,即不会进入按键中断处理函数,此时ev_press = 0
X! ]' l8 R v! ^- O2 l) d * 当按键按下时,就会进入按键中断处理函数,此时ev_press被设置为1
3 i* Y' u+ T2 J7 g- `$ O3 M$ d) N C */; V2 B2 w7 V/ h2 J
if(ev_press): t" G; q" v7 ^9 L- S, o
{
U4 x+ A% K* f( M3 V$ e0 ]1 D* T mask |= POLLIN | POLLRDNORM; /* 表示有数据可读 */
$ x* h, S1 m) Q& {0 x/ W$ F }
5 R% j6 `& d2 M! S' h2 I
$ t. L5 i0 H7 k4 _/ H. | /* 如果有按键按下时,mask |= POLLIN | POLLRDNORM,否则mask = 0 */% Q7 W$ L4 V! D/ r8 s" E
return mask;
1 p: ]/ N3 g; \6 B, o}
, u% G$ Y5 E2 f9 q
. t+ w& c3 O- ]+ s0 j/ Y/* 当应用程序调用了fcntl(fd, F_SETFL, Oflags | FASYNC);
+ \! R6 ^) R+ C; C4 e * 则最终会调用驱动的fasync函数,在这里则是fifth_drv_fasync& I3 ?2 \5 o* F: l6 j
* fifth_drv_fasync最终又会调用到驱动的fasync_helper函数6 O% W$ t4 H& h2 H
* fasync_helper函数的作用是初始化/释放fasync_struct
' d+ J0 ^6 r, ~& P */) I/ c/ L( e# M) ` s5 j) G! l
static int fifth_drv_fasync(int fd, struct file *filp, int on)
3 R: ^7 q) f% {- e{
) d3 c4 p0 t2 ]% H return fasync_helper(fd, filp, on, &button_fasync);' x* |/ A3 e( j& W; q
}
* F! U, R4 p- e
& w, v. o( E: W/* File operations struct for character device */" H+ ^2 E1 c. n2 O; {9 ~
static const struct file_operations fifth_drv_fops = {
! r! h2 m0 y4 d .owner = THIS_MODULE,# m& o& S# U, `5 b( T
.open = fifth_drv_open,
' i9 \2 o$ R7 s5 ?+ ? .read = fifth_drv_read,
0 b8 \4 V8 f+ b .release = fifth_drv_close,
& b& J) [* h( _, M% f# z" v1 q .poll = fifth_drv_poll," ?+ s# ]6 S3 ]+ k; C, R* ^% f# u5 ^
.fasync = fifth_drv_fasync,
: I7 }5 s+ x7 Y};& D5 }# l. p5 V
* C7 @, T1 @/ A: b# f- f/ a& y
; V X+ k. O0 ]0 e6 O0 y/ m2 ]6 y
/* 驱动入口函数 */, ]* D4 a) \" B2 _1 ?& _2 i' L
static int fifth_drv_init(void)* ]2 t5 L3 v, H3 j: l' K r y
{0 B/ {, z1 \/ n5 J9 \9 V0 q" i
/* 主设备号设置为0表示由系统自动分配主设备号 */5 X( }- i+ ~# [( F/ L
major = register_chrdev(0, "fifth_drv", &fifth_drv_fops);
9 Z2 n: v" K! N5 J: J) s- M, J o$ N) _, t" L+ ]; T. Q$ r' U
/* 创建fifthdrv类 */, z ~3 z1 P! r& d* z
fifthdrv_class = class_create(THIS_MODULE, "fifthdrv");
6 m% V: h8 ~ F9 g2 \
( g' _: M9 h4 Y) A) f /* 在fifthdrv类下创建buttons设备,供应用程序打开设备*/& X6 G2 y4 |7 Q( C) ]
fifthdrv_device = device_create(fifthdrv_class, NULL, MKDEV(major, 0), NULL, "buttons");
1 r$ Y- A( o& g* L. v
. N, P% N/ G1 S) Q1 C$ g* l6 E! B: k2 V return 0;
, c0 O3 K5 I9 d ~& V) Y( n: v}( N# U5 A/ A: Y0 n7 [. ]
, o: K: K$ S! j7 z7 \. V: i) T
/* 驱动出口函数 */8 U% c' F8 Q4 ?9 e2 c1 }8 d
static void fifth_drv_exit(void) }5 T% J" R; a1 M O$ |: |
{6 l8 O& g. [7 i$ V% Q# W$ C
unregister_chrdev(major, "fifth_drv");
0 F7 t6 {5 x7 X% |. s% p device_unregister(fifthdrv_device); //卸载类下的设备
7 i; H6 w: m8 e% N7 A7 S j class_destroy(fifthdrv_class); //卸载类* w: v& u9 s3 l3 _( ?- X
}7 t! q& P' C7 p5 U" T( d" \
}1 }' v& Y/ p: @# [
module_init(fifth_drv_init); //用于修饰入口函数
6 G) h) u, V; b m9 F% Xmodule_exit(fifth_drv_exit); //用于修饰出口函数 . ]* ~' d* u/ ~+ f% F8 g8 c/ ?
5 ]! }8 b- N; P) S1 p- E+ V
MODULE_AUTHOR("LWJ");' [: ~( {/ V5 I% r1 Q7 D- F
MODULE_DESCRIPTION("Just for Demon");; U2 g p2 V8 w" ~3 @8 ?! M
MODULE_LICENSE("GPL"); //遵循GPL协议
7 ^& s* p, n& r, ~/ {( d; N$ ]- ^8 N9 `$ J; D
应用测试程序源码:
8 h9 i! P" j" Y3 g# _5 C* i
, D6 r; f3 P, c( ^$ M#include <stdio.h>
5 w+ [: R, j2 D9 O9 J5 ^#include <sys/types.h>
( g( w! F3 V* y( Q; m8 N#include <sys/stat.h>7 t) J' |5 Q x- y6 F+ V0 O- Y
#include <fcntl.h>
; @& m0 r4 q- X; l2 O+ o4 l3 i$ x( l#include <unistd.h> //sleep
4 u8 K- n- c# s: d#include <poll.h>3 @) v1 @+ h4 g( H& V2 @7 ^
#include <signal.h>
+ M! g; r9 k3 j& h) |# p#include <fcntl.h>
+ q& j0 t* r& @2 {9 S* Z7 g) w& D
int fd;6 p/ `- T: z. N" Z9 C: s
; A; F/ L& o" ^' h7 l+ lvoid mysignal_fun(int signum) e T& q1 P* Q+ c! d
{+ r+ O- d& q, E( g* Y% x
unsigned char key_val;
3 g' ?* f( p7 s$ U read(fd,&key_val,1);8 } L! I2 a9 Y8 q$ b9 i: J& V2 ?
printf("key_val = 0x%x\n",key_val);
2 e5 N- b" \7 m% z- f7 w1 i}- y# R4 B" k F% y
8 O0 n0 J) N; F0 U
/ U4 X% K5 [ i4 u, c/* fifth_test
* K* | i) J7 z/ y */
+ W# n/ S% n& C Z- e/ ?int main(int argc ,char *argv[])
7 k# D6 }7 G6 ~/ n9 c. n{
/ f2 s6 z7 |/ Q# P! U8 g3 Z1 x int flag;
' E2 E8 k! Q/ P0 _ signal(SIGIO,mysignal_fun);" x" z+ \5 X/ C$ c
' [4 q% e) X, G6 s* z; D
fd = open("/dev/buttons",O_RDWR);
5 g8 N/ ]- `) z5 g if (fd < 0)
4 G# R/ y; V& j, |2 e6 ~5 B+ M- i {
7 Z0 B% R* ?' T5 |* i printf("open error\n");6 c# A9 I' {' ~- E) P4 u5 M
}
3 a2 e* i. V6 X
+ h1 r5 [/ C+ r) r% ^4 r /* F_SETOWN: Set the process ID
0 U/ k4 i+ }5 X% c0 o: }4 ~ * 告诉内核,发给谁" f* \* w! R7 {, r
*/
- J f0 E/ E4 ~% v2 C! Z: U fcntl(fd, F_SETOWN, getpid());
# m& L0 ?/ f' j+ n( _
& b+ B# i% s3 e6 M /* F_GETFL :Read the file status flags
2 u) K2 S r5 n * 读出当前文件的状态- S5 w- g- N: V6 Y' \
*/2 u( H' @; {" b9 b
flag = fcntl(fd,F_GETFL);
9 c, w- j- h! e8 h0 f8 x4 r u' p) {
* X! X, U0 ^2 ~" P /* F_SETFL: Set the file status flags to the value specified by arg2 X. ^" B6 ]' Y/ ]! V; r: @* j/ ~
* int fcntl(int fd, int cmd, long arg);0 V9 E& D3 ^& Q, ]; k% W
* 修改当前文件的状态,添加异步通知功能+ H# \2 ?0 J- z& q" e) D7 K% p! q
*/
3 v5 T' j, S% Q; ^. h7 i fcntl(fd,F_SETFL,flag | FASYNC);8 d7 {1 [0 i# n& F5 S
# c- @0 w7 d h5 v' j5 M' P while(1)4 R( u J1 d2 Q4 g4 F! O
{
8 Q2 d3 C6 `5 V7 n/ E5 h. s /* 为了测试,主函数里,什么也不做 */
- K$ C) [; C. k7 p0 U; j sleep(1000);, C- C1 J7 q) N6 y2 b# p {+ f# _0 m: {* ^
}
' c% u% \( @( U# W$ c3 A2 q return 0;$ L7 h5 K) e1 |
}
# o5 m# J: N, }% ^, H. I2 k2 x0 D3 A6 ~
测试步骤:$ [- D! u1 r( v, _
& ?* S2 y3 E0 w9 N% t[WJ2440]# ls
+ Y* H0 H- u0 wQt fifth_drv.ko lib sddisk udisk) C, p- h, B! w' A8 G; ^
TQLedtest fifth_test linuxrc second_drv.ko usr
. A- x' q* F- _; D5 V, L s! b Eapp_test first_drv.ko mnt second_test var2 N3 l, p; X' b
bin first_test opt sys web
; f( M8 ]) j& U4 p6 e# Mdev fourth_drv.ko proc third_drv.ko
& e& q& S _# d' Q1 @5 Pdriver_test fourth_test root third_test4 Y2 a5 W& }+ N) k
etc home sbin tmp' w6 w6 I, U6 D* j7 A& R
[WJ2440]# insmod fifth_drv.ko , y. C8 y2 A! s, f
[WJ2440]# lsmod% _- y: r( T8 b4 @# ?
fifth_drv 3360 0 - Live 0xbf006000; p- Q0 O3 J: ~2 {$ M3 x
[WJ2440]# ls /dev/buttons -l3 c6 _: F: e, |2 C' A; y
crw-rw---- 1 root root 252, 0 Jan 2 04:27 /dev/buttons
$ C" |0 n$ J5 _$ ?0 i9 u! {0 K+ a1 ?[WJ2440]# ./fifth_test # a0 ^: z! N2 d4 W6 C) W9 x8 M' B: S
key_val = 0x1
2 ?/ f# }: ?% W, u8 W7 ]# f* z( B: nkey_val = 0x815 e* s& y1 J8 Q: v
key_val = 0x4: D" I/ A% h& @( X; e
key_val = 0x84
) ^* i9 N/ s; Ekey_val = 0x2
# ~( [5 [: y. V$ k" ?- skey_val = 0x825 d1 x$ [" K! r5 P) X$ q
key_val = 0x3
5 K0 l+ |+ s0 j `key_val = 0x83
: r5 V/ _: G6 e0 y* f2 I9 Ykey_val = 0x4
# {; i; @. q9 {5 b! fkey_val = 0x84+ m! h. g! T/ }2 T
key_val = 0x844 y- {: x3 ~) k: ~
6 W/ n9 v; C1 ] C
由测试可知,当无按键按下时,应用测试程序一直在sleep,当有按键按下时,signal会被调用,最终会调用mysignal_fun,在此函数里read(fd,&key_val,1);会去读出按键值,这样一来,应用程序就相当于不用主动去读数据了,每当驱动里有数据时,就会告诉应用程序有数据了,你该去读数据了,此时read函数才会被调用。2 }1 Y( A# t0 F' u) f
* {" q! x) E7 q9 M
: a: G" y( x( ^- |
这里最后总结一下老师的笔记:% W# O. A2 N W5 D6 f$ X
4 F! f; Z- l; B6 ]
为了使设备支持异步通知机制,驱动程序中涉及以下3项工作:
" K% N* }* R) b' d1. 支持F_SETOWN命令,能在这个控制命令处理中设置filp->f_owner为对应进程ID。% D0 p! @% V3 l3 A, W* p8 ^, D7 u
不过此项工作已由内核完成,设备驱动无须处理。! {. \& J; e7 a A- f" I3 z
2. 支持F_SETFL命令的处理,每当FASYNC标志改变时,驱动程序中的fasync()函数将得以执行。
& U7 u. J1 b g+ p+ O+ [5 u 驱动中应该实现fasync()函数。
# ?2 A/ g* m1 N2 ~3 `3 q3. 在设备资源可获得时,调用kill_fasync()函数激发相应的信号
% X/ f4 l2 R1 V. j2 L/ Q( e' `9 R1 J1 y4 R9 l2 [: g! R3 s
应用程序:6 o2 U, u' z+ T1 Z- Q5 |
fcntl(fd, F_SETOWN, getpid()); // 告诉内核,发给谁# X1 m7 G3 ]. X( N" @: f
7 V9 Y1 a* g( g% P3 V
Oflags = fcntl(fd, F_GETFL); $ D3 b& y2 i: p* a* c
fcntl(fd, F_SETFL, Oflags | FASYNC); // 改变fasync标记,最终会调用到驱动的faync > fasync_helper:初始化/释放fasync_struct
5 z) _: W+ p$ R7 n8 J& s$ Z
2 l: _* S( X0 z8 X
$ l+ [4 J& |! g; \1 {6 e" l3 x3 a: b/ i4 @) k
|
|