找回密码
 注册
关于网站域名变更的通知
查看: 257|回复: 1
打印 上一主题 下一主题

linux字符驱动之异步通知按键驱动

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2020-6-9 14:57 | 只看该作者 回帖奖励 |正序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
在上一节里,我们在中断的基础上添加poll机制来实现有数据的时候就去读,没数据的时候,自己规定一个时间,如果还没有数据,就表示超时时间。在此以前,我们都是让应用程序主动去读,那有没有一种情况,当驱动程序有数据时,主动去告诉应用程序,告诉它,有数据了,你赶紧来读吧。答案当然是有的,这种情况在linux里的专业术语就叫异步通知。
$ ?& o6 E% {- j& H0 s, E+ @; Q( E! V1 Z
上一节文章:
0 G2 l1 g6 N& c7 _* E, i& ?, K+ }2 o! G

* u& ?, G6 R1 e! u在这一节里,我们将在上一节的基础上修改驱动,将其修改为有异步通知功能的按键驱动,目标:按下按键时,驱动主动去通知应用程序。
" C0 Q0 r  _$ J5 a1 Y6 t: C$ [& t* L/ J
问:如何实现异步通知,有哪些要素?
: Y- K* Q" B: l) V8 _2 S/ W' p  A: `. m. ~1 H4 X+ v
答:有四个要素:
4 y! A: V% O( D  l. t
/ m( C% A, s. Z) y; C; j- \( u一、应用程序要实现有:注册信号处理函数,使用signal函数8 F; h# H2 J: m- Z

7 B  x% v1 q, U3 e$ T二、谁来发?驱动来发8 N3 s& ^& u, |$ a$ r
) Z0 e8 a. U6 Y1 M& @4 C: s
三、发给谁?发给应用程序,但应用程序必须告诉驱动PID3 c: Q+ k4 Q, I- g
+ O  \) ^  X+ \! f8 N4 u' H9 G
四、怎么发?驱动程序使用kill_fasync函数
) u2 F% J  [* K' ?% ^5 X6 H% [
6 |, B) O& l3 Y. D$ S0 W问:应该在驱动的哪里调用kill_fasync函数?
% q% g3 I, k& [& X* w; U
( \3 r: `$ d% h" ?! Y& O答:kill_fasync函数的作用是,当有数据时去通知应用程序,理所当然的应该在用户终端处理函数里调用。4 U; S0 |+ N$ \9 D5 F! W# f

. z6 U. \' {5 v  f问:file_operations需要添加什么函数指针成员吗?/ ^7 T" o3 @* P, M8 b( [
" `  U% M6 f$ ^. N; s& g
答:要的,需要添加fasync函数指针,要实现这个函数指针,幸运的是,这个函数仅仅调用了fasync_helper函数,而且这个函数是内核帮我们实现好了,驱动工程师不用修改,fasync_helper函数的作用是初始化/释放fasync_struct9 k8 x% M9 I- @! C( b  J# D0 q
8 T3 i# ~  K# T) }
  O9 r+ k6 P% B
; A. V9 ?  N3 V( T; T, G
详细请参考驱动源码:. e2 \5 o+ h" C4 {

9 D# ^! F2 K! b' b6 V# e5 ~
3 `  d7 Y& U  Y2 B: J! y. k#include <linux/kernel.h>3 ]* j, Q# `4 r1 ?4 H
#include <linux/fs.h>
0 A# X1 d0 f1 V8 y& S* o, T#include <linux/init.h>
( z* G, L3 i6 ~#include <linux/delay.h>
: w% `  S7 P$ ~# [, ^. ^8 ]. l+ Q#include <linux/irq.h>
' N* _0 E( I+ d#include <asm/uaccess.h>
) f- [: @8 z8 w4 w4 L( P7 n0 c#include <asm/irq.h>
( b) Z, Q' {. ~* \& _' c#include <asm/io.h>( _9 [0 X& ?% K1 A( n
#include <linux/module.h>
6 u, t% v6 A4 b* C) v#include <linux/device.h>                 //class_create
/ Z2 @, M, A( _9 g) G0 s' V# Y#include <mach/regs-gpio.h>                //S3C2410_GPF1( {+ \$ h5 q6 n' L" s; K5 K+ d
//#include <asm/arch/regs-gpio.h>  
. z! E& \  ~- w#include <mach/hardware.h>
! |% l; I; d9 G6 |//#include <asm/hardware.h>
# \1 B! R" q# P2 b+ O5 D# V4 W( x#include <linux/interrupt.h>  //wait_event_interruptible, S( i: d4 E( L9 z
#include <linux/poll.h>   //poll% ^4 l2 `: d) P' w6 y7 |
#include <linux/fcntl.h>7 B) }8 q, ~9 U, R4 d: a
* |, L' c2 h* G5 n  [# |
4 l$ U% L( ^) w% G8 W
/* 定义并初始化等待队列头 */
' L" z) @; o# b3 s+ Ostatic DECLARE_WAIT_QUEUE_HEAD(button_waitq);$ H" N- |* q) s5 T% m- Z

- Y* I* h- w6 c+ }8 f3 O) R& E) V  b+ t- Q  \. u. |, U  p5 \! {3 ^
static struct class *fifthdrv_class;
/ Q, ?/ G6 Y( ]; i  L- `: x# Z3 t) zstatic struct device *fifthdrv_device;) d) Q, S! A. t" I8 ~
1 @' s; M- _" }2 H2 p* [, u7 ^! s
static struct pin_desc{
3 z" ]% O4 Y; p/ a; s( H        unsigned int pin;8 }# _- p- `" \2 L. n, F
        unsigned int key_val;( h# z% x2 I) k  o, U2 w# [2 t
};+ p3 M4 c7 t. V6 {. X; q6 I
: K; _0 v- Y7 `" [, K$ K, p
static struct pin_desc pins_desc[4] = {
6 U  l- s4 o' i                {S3C2410_GPF1,0x01},) V! v6 x  _4 w+ y: \5 C
                {S3C2410_GPF4,0x02},9 _, G% g# U" Q- W+ t, }
                {S3C2410_GPF2,0x03},
6 G3 j% c! H+ x8 [6 J" [                {S3C2410_GPF0,0x04},& z1 v3 {8 _1 J0 g4 r+ S( E
};
0 w* @, }! \2 I9 H* S# M0 ~$ f4 A. a4 B; S+ o- ^
static int ev_press = 0;
4 {. G  i" N# B8 r, Q/ X9 W; K8 v' y/ _, u' u
/* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */
- X' S& O- n5 V, v9 M( ~/* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */) K( X9 d5 h1 i
static unsigned char key_val;& U% J  [+ r: ^7 r6 X
int major;- Z+ [0 m7 l1 D1 S
( X% @5 S( X7 u$ d. b4 L: P: P8 G
static struct fasync_struct *button_fasync;
+ h/ k* l# N$ G- y$ G2 |! g' ~# g/ d- Q. Z8 ~
/* 用户中断处理函数 */5 p# k- M5 T0 C
static irqreturn_t buttons_irq(int irq, void *dev_id)
/ J' L( a% F* H{; ~( D5 w/ l" ^  K  `% ]
        struct pin_desc *pindesc = (struct pin_desc *)dev_id;6 m1 L; z) l8 Y7 k4 G% E* R
        unsigned int pinval;
9 k! z& F* L2 a7 M- r/ _0 f        pinval = s3c2410_gpio_getpin(pindesc->pin);1 e! ]- Y9 e9 \5 g! R

$ D6 v. {5 F7 I" x+ V0 z        if(pinval)
9 D2 u  p' X5 G4 H5 i        {
4 X* S' }4 F+ C" J                /* 松开 */
! f9 }: @$ i: |/ C' ~4 d# Y                key_val = 0x80 | (pindesc->key_val);
& D4 [5 K6 s/ q% f+ v( z: L        }
7 X8 e6 ^9 S- `; m" K7 t        else5 X! A* l9 K" t
        {4 N) G6 b' s! ^* B+ Y4 r
                /* 按下 */
4 v* ]" T, e2 S5 ?* A& }                key_val = pindesc->key_val;! k' g- B* T# `: S! ^5 E
        }
9 ]7 a; L8 I# s  e
! b  |7 b. A" i        ev_press = 1;                                                         /* 表示中断已经发生 */; J, Q% Y" D7 E2 n  \. a6 t
        wake_up_interruptible(&button_waitq);   /* 唤醒休眠的进程 */
; k  U9 m5 O9 A6 N* c! m  L
7 K" M' `9 Y! j        /* 用kill_fasync函数告诉应用程序,有数据可读了 . W* F& j4 a5 c- b  q1 E
         * button_fasync结构体里包含了发给谁(PID指定)
8 E4 `$ ^( z. r% H* u         * SIGIO表示要发送的信号类型
- \2 C' B! R. ]3 L- [* d4 g7 ?, @4 O         * POLL_IN表示发送的原因(有数据可读了)3 P! v& h% r9 S/ u& _& w' m
         */; b1 q# [1 G, p$ Z, p
        kill_fasync(&button_fasync, SIGIO, POLL_IN);! y! `9 x1 c9 D
        return IRQ_HANDLED;
$ O& r) E1 A. R" g1 e: W1 ]/ Q}
) t4 K, _; h$ @static int fifth_drv_open(struct inode * inode, struct file * filp)
( @/ T; R' e2 |; \) P% s{
# v- V( V! g$ M- m1 {        /*  K1 ---- EINT1,K2 ---- EINT4,K3 ---- EINT2,K4 ---- EINT0
3 q9 y! Y; n8 l' B$ {           *  配置GPF1、GPF4、GPF2、GPF0为相应的外部中断引脚* v$ O5 k+ G' T  @# z1 b) s& S
           *  IRQT_BOTHEDGE应该改为IRQ_TYPE_EDGE_BOTH
3 n, h, Q9 _1 [8 [- ~, p+ v         *// i9 j8 Z3 `+ L* Y8 A& m
        request_irq(IRQ_EINT1, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K1",&pins_desc[0]);
# v( m: S8 G7 h1 X$ H1 Y# q        request_irq(IRQ_EINT4, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K2",&pins_desc[1]);/ f  F. Q" r6 V; E, |4 i
        request_irq(IRQ_EINT2, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K3",&pins_desc[2]);" ?0 c4 M1 F. v( s
        request_irq(IRQ_EINT0, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K4",&pins_desc[3]);
/ y' B0 y! T% L! T; s# D9 M4 M+ g        return 0;/ |+ y' a. _8 d2 X* O% o
}
/ m1 g5 J7 v+ z$ A" v  B
1 c$ _1 @- R& V3 P* y0 zstatic ssize_t fifth_drv_read(struct file *file, char __user *user, size_t size,loff_t *ppos)
  ^; ]* L4 r, m{1 b3 e) \7 [/ ^
        if (size != 1); x6 m+ h6 M0 y$ `
                        return -EINVAL;# ~3 O6 O8 f8 {' u" L( _3 t$ c* s
       
% {* \9 D0 @* I; z, o9 j) ~        /* 当没有按键按下时,休眠。
9 y8 ^  p+ E2 U1 h         * 即ev_press = 0;# ^4 T& Z6 i0 o6 y( C2 [
         * 当有按键按下时,发生中断,在中断处理函数会唤醒
, E. A$ L0 j" ^; p         * 即ev_press = 1;
% u1 }3 k7 x2 s# N" d; a         * 唤醒后,接着继续将数据通过copy_to_user函数传递给应用程序) [) G+ V- h5 M9 ?% @$ H
         */8 n+ ~+ s! ?* C) p: L, U5 ~9 C3 C
        wait_event_interruptible(button_waitq, ev_press);; o* C" j" X/ n" R8 z. B
        copy_to_user(user, &key_val, 1);7 m1 u' `0 c8 x/ w
        5 j' C9 Y/ ]" o: ~) J7 t4 G
        /* 将ev_press清零 */# g5 |% l& p3 Q
        ev_press = 0;
3 w: v/ p+ H9 K! e' ^) ^5 r. u/ l        return 1;        ' T' N% C  U+ ?
}
# ~! ?0 e/ [% ]- n; O2 r
2 I* F8 L8 H+ \& bstatic int fifth_drv_close(struct inode *inode, struct file *file)- A  E3 d! G( a5 J$ F" N
{6 A( w' F: b% ]2 U; n4 X" Z
        free_irq(IRQ_EINT1,&pins_desc[0]);0 y  q- R; ~* _1 ~; Y
        free_irq(IRQ_EINT4,&pins_desc[1]);2 M" t- Q' o5 k, n
        free_irq(IRQ_EINT2,&pins_desc[2]);
% A3 y4 K8 C2 I" {        free_irq(IRQ_EINT0,&pins_desc[3]);/ C- ?. O% L" K' b$ E. d
        return 0;: q6 }7 S+ z6 Y& [- y, W9 \: i9 D6 r
}
6 i& F9 S1 n7 w( s* C% Y4 y/ u! k% ?1 G5 w9 x
static unsigned int fifth_drv_poll(struct file *file, poll_table *wait)
* m5 K6 k0 I- y3 _1 x) c# ^{# C# {7 y" n; q/ |4 U' x# X. [
        unsigned int mask = 0;
, H( r4 g2 r# \/ u: c, g" X: V1 {( ~/ r: y" Q
        /* 该函数,只是将进程挂在button_waitq队列上,而不是立即休眠 */
5 y; W6 U1 I; S$ {5 H2 @# a- |* \& R7 O        poll_wait(file, &button_waitq, wait);9 F) @6 l1 U: J; N* P
& h2 `4 j+ q+ N3 w' v  u6 E
        /* 当没有按键按下时,即不会进入按键中断处理函数,此时ev_press = 0 & E' j& h" Z3 p) S8 z9 {6 g
         * 当按键按下时,就会进入按键中断处理函数,此时ev_press被设置为1
4 E3 V, `. D, @$ o& P         */& ^3 o4 j9 A& `, ~, n
        if(ev_press)0 h- [# ?) N6 r3 {0 ~2 U- o
        {1 q0 m3 W' B" ]% k+ n/ @$ ~
                mask |= POLLIN | POLLRDNORM;  /* 表示有数据可读 */
) D$ x! U- }3 V/ d# y$ D        }
. i$ E2 [4 \. k! Q/ T% E1 j- Q6 C5 \9 @
        /* 如果有按键按下时,mask |= POLLIN | POLLRDNORM,否则mask = 0 */; x2 D  \+ Q9 w. a/ Q  n6 a" e
        return mask;  ! P5 O+ e* S. {9 K, L
}
: R) \$ }! h# D+ O3 f# K1 e5 o/ C, Q" z7 b
/* 当应用程序调用了fcntl(fd, F_SETFL, Oflags | FASYNC); * K6 w4 [/ T- A$ A( ]- X* M2 J% ~- U  J
* 则最终会调用驱动的fasync函数,在这里则是fifth_drv_fasync+ x" h7 L# L/ V
* fifth_drv_fasync最终又会调用到驱动的fasync_helper函数
3 j, x# v- Z2 e, c# Q- z; J( q3 [ * fasync_helper函数的作用是初始化/释放fasync_struct, _9 }; l% G2 X
*/
/ k0 s7 C! L1 z" xstatic int fifth_drv_fasync(int fd, struct file *filp, int on)
1 z1 C6 j2 C$ |$ T1 k; c6 L{
8 R5 o& M4 O3 d0 M        return fasync_helper(fd, filp, on, &button_fasync);0 _2 G6 Q) Z4 \# d; m# S; e% I
}2 H/ G' s" `7 b4 C8 N2 q7 v' r

* l9 G& X; v8 J  F$ r6 O2 `/* File operations struct for character device */
* l+ A, D- V5 [static const struct file_operations fifth_drv_fops = {& l' u! _# X- w
        .owner                = THIS_MODULE,
9 q8 L. I1 s. Q% u        .open                = fifth_drv_open,9 r6 I1 ~& a, |$ f2 @. l
        .read                = fifth_drv_read," X! {3 l" a/ o& j
        .release    = fifth_drv_close,2 Y, |, q3 [& i/ b1 |4 p
        .poll       = fifth_drv_poll,
; O& ~8 q, U$ s1 q        .fasync                = fifth_drv_fasync,4 K; \' c/ O2 {0 a2 A, Y0 y8 Z0 G
};$ l( J$ [7 N- ]+ b$ ]: v

1 u1 t7 }+ N: n0 `0 w9 W( b: v4 H; D. M
/* 驱动入口函数 */5 V- z2 V' t8 @% h$ i8 o& b
static int fifth_drv_init(void)
7 @& @, [, X" A0 Z: Z{
4 h9 D" {# X) F! x3 I. r, a        /* 主设备号设置为0表示由系统自动分配主设备号 */3 D9 g1 ^  ]) L( N- p- e( d
        major = register_chrdev(0, "fifth_drv", &fifth_drv_fops);
- b6 y; e# [$ l$ v( {' k. Y4 i1 H3 P6 T/ n, a% A. d1 S  S7 ]
        /* 创建fifthdrv类 */* }7 o& y/ G1 S  O
        fifthdrv_class = class_create(THIS_MODULE, "fifthdrv");8 R! P- g* ~; i% ]% Z
  a9 b8 e- }; Z& w# u; C8 P- V
        /* 在fifthdrv类下创建buttons设备,供应用程序打开设备*/
% j9 _3 n5 U# D8 G6 x0 u4 @5 k        fifthdrv_device = device_create(fifthdrv_class, NULL, MKDEV(major, 0), NULL, "buttons");
% O- g% T: E  |
! W5 f6 R2 B  P        return 0;! D7 O; o/ l2 A
}
& \' K# ]- {3 [7 R% U+ @6 N
! j& O( K) s# z/ f: Q/* 驱动出口函数 */4 f. s" Y; M3 u4 O
static void fifth_drv_exit(void)5 U, T0 `0 ^, I7 B+ X% C/ ~
{
6 H- j8 m" i) Z3 y        unregister_chrdev(major, "fifth_drv");
* _, `6 M* g) L" l        device_unregister(fifthdrv_device);  //卸载类下的设备0 q( O# Z" @. f8 {+ T3 s
        class_destroy(fifthdrv_class);                //卸载类
+ f& B8 Q3 T/ }" s$ p; B. r}
9 {( x3 y8 ]2 P9 W6 k$ R, B5 \# J3 Z; W1 R) [: a- M% i7 e
module_init(fifth_drv_init);  //用于修饰入口函数/ ^8 c: U- m$ w8 H+ K
module_exit(fifth_drv_exit);  //用于修饰出口函数       
" t$ J/ \) H* }+ V6 M' V4 P( t$ I. g0 Q. J
MODULE_AUTHOR("LWJ");' H( X/ t/ R; O) k5 H3 E' z5 ^; w
MODULE_DESCRIPTION("Just for Demon");# h& R; l, ^4 ?! N0 ]! t
MODULE_LICENSE("GPL");  //遵循GPL协议7 j5 I2 }9 F9 I4 {

* Z$ S! Q8 c$ L8 L1 v应用测试程序源码:
. g! r" T7 _' [3 x. z* P- _5 ^# i9 Y6 L; _! y' I
#include <stdio.h>* ]$ B7 w4 [* o, U
#include <sys/types.h>
2 X; ~  `/ h/ T0 c& P6 D" Y* I#include <sys/stat.h>  V! m1 v  T$ H9 F% F( n
#include <fcntl.h>
( V0 J1 j; J* f) v9 E; o7 }. {  O#include <unistd.h>        //sleep
! {0 J9 B9 T& J- l& l, u#include <poll.h>
2 T: P$ n6 W7 E! a#include <signal.h>' ], ?/ S) B* i' f
#include <fcntl.h>
3 b7 [0 O, B! M- f% w8 o0 {# L
1 H' a, t3 y/ G; e& G. Qint fd;
% L8 v' o4 ^$ I' T( v/ V# o
0 K6 @# F# i' k9 L, u8 b9 Nvoid mysignal_fun(int signum)" O* A' Q. O* V9 ]& m! ~4 Q" A: w
{# j  x# O  U& x* [
        unsigned char key_val;
2 a, T  h% q& E6 n        read(fd,&key_val,1);( q* n- @. N. F9 p$ n9 \; S
        printf("key_val = 0x%x\n",key_val);7 c8 G) r. Y5 H8 l" g4 }4 S! i" h( Z
}
" F" f) F5 j. {3 d8 }( j/ h: X9 {& T* v4 i
( i/ Q. \/ b- x; r9 F; n1 R
/* fifth_test
% I) D5 t) x5 h9 u* Z2 R! e  s */ 3 y9 u) D. S  t$ |% c
int main(int argc ,char *argv[])! Q7 H7 y3 R. Q0 r
{. O  L1 _4 l5 \; B2 D
        int flag;
4 b0 w% {: ~- N" g1 M# F1 |* p# h        signal(SIGIO,mysignal_fun);5 Q; X7 k! @6 ~* D; s: O

- K( M, }! h4 Z5 _- _" ]        fd = open("/dev/buttons",O_RDWR);
' H; O* ]9 Q+ ~  O        if (fd < 0)
* M& \" w. \4 H" h# X        {
4 M/ w6 x, `6 q& k: o                printf("open error\n");" }" o6 ~7 o3 j. U/ v
        }
4 v+ d4 Y. P$ a3 a% N6 a) m
5 o2 I& n3 G- o6 l% A8 ?# Y        /* F_SETOWN:  Set the process ID
' j4 F% \) F5 o& v         *  告诉内核,发给谁
; I& S/ P8 S; X; ~4 ]* W; v9 D5 M         */
8 Q# ~8 R* Q8 h0 k5 n2 K% O7 _; P4 i        fcntl(fd, F_SETOWN, getpid());
7 x4 V4 y6 ?" L" c% O9 x; q( }3 a% Y% F) e4 v" {
        /*  F_GETFL :Read the file status flags
# E1 s- K7 K3 Q1 K         *  读出当前文件的状态
# M8 ]0 P1 f7 r2 E         */  x7 l; R) G9 k! C5 _1 I! y% q
        flag = fcntl(fd,F_GETFL);
* t& e8 F& _& i% i% p8 k4 E( B
1 |" e% [; h( \+ o        /* F_SETFL: Set the file status flags to the value specified by arg; }( E  V  Z3 ^% N4 T8 m0 |% i
         * int fcntl(int fd, int cmd, long arg);
9 M, O9 N8 W) a! z) k         * 修改当前文件的状态,添加异步通知功能. m' P' J5 }- q. Q" W
         */
6 k: S- [( g$ F) G# H' i        fcntl(fd,F_SETFL,flag | FASYNC);& e9 w6 a& D+ y2 X! f
        . E' l; M8 H5 G' {- _8 M9 G* o
        while(1)" t7 g9 b, f8 w( ^8 j  B! w5 B
        {
' b; Q) K5 `" [; o# T4 r5 p                /* 为了测试,主函数里,什么也不做 *// `# c2 v+ w4 ]6 n4 a
                sleep(1000);; V- i' {3 d# j! u9 x  v
        }
8 ]' ?" |4 J5 c8 q' ]: X5 }5 j( ?        return 0;! p" Y0 c2 W; I* m( }
}
1 ^) O* l% A; O9 ]# g9 [" T6 u5 B* h
' `- i/ J5 U- N$ y; `% r测试步骤:6 L2 F8 k* J3 `# s# V5 o
, k3 j5 g- T$ S
[WJ2440]# ls
1 P5 U! z/ G' T" aQt             fifth_drv.ko   lib            sddisk         udisk
0 [1 e( s' b+ C$ lTQLedtest      fifth_test     linuxrc        second_drv.ko  usr* E! i# l6 e$ s! R
app_test       first_drv.ko   mnt            second_test    var' Q0 Y# z% k5 w: G5 ^# M
bin            first_test     opt            sys            web
( V: x8 e# Q& U, |3 c& vdev            fourth_drv.ko  proc           third_drv.ko" I# p  d3 K4 }. {. _5 s
driver_test    fourth_test    root           third_test
! }9 V- D6 E+ D/ l' g- wetc            home           sbin           tmp. y( ?2 B) Q* [- o4 F
[WJ2440]# insmod fifth_drv.ko & w+ ~* q' [6 g( I: m% `& K% n
[WJ2440]# lsmod
3 x# c! t6 r8 R' N2 L4 x: [' E" I) X; T0 Afifth_drv 3360 0 - Live 0xbf006000
0 E: `* e9 ^& Z9 Q4 K' y[WJ2440]# ls /dev/buttons -l
6 p0 m% X, D0 M  y7 O$ ^' R) Vcrw-rw----    1 root     root      252,   0 Jan  2 04:27 /dev/buttons. e6 A8 c3 Y3 i$ B" f8 p1 L
[WJ2440]# ./fifth_test
$ h+ r# x3 k0 Bkey_val = 0x1! k1 O' Z! H% C2 f+ |3 i: O) O
key_val = 0x814 b! j* A9 w5 e$ V# }' X1 i
key_val = 0x4
. }7 i  F# j( ?* q. Okey_val = 0x84: I$ N$ m0 R& t# t0 V5 H
key_val = 0x2' R0 X' L) Q5 r
key_val = 0x82
; I. N% P, g8 m+ U; c1 Q) C% h0 Ckey_val = 0x3+ ]  {: n9 u* ]( G% r
key_val = 0x833 z5 y) D3 S& u) }& Y
key_val = 0x4
) o7 ]+ Z& K! Z" q5 j% ?key_val = 0x84# X9 B" t% N+ }) i) I
key_val = 0x84
# r$ d; K7 q) @9 }& k' Q
( ^( N% m9 W$ H0 N由测试可知,当无按键按下时,应用测试程序一直在sleep,当有按键按下时,signal会被调用,最终会调用mysignal_fun,在此函数里read(fd,&key_val,1);会去读出按键值,这样一来,应用程序就相当于不用主动去读数据了,每当驱动里有数据时,就会告诉应用程序有数据了,你该去读数据了,此时read函数才会被调用。
3 @; L/ N: B( N# x$ O
- w. H# i" o8 m% G7 s
8 N7 g0 ^* J& O6 l这里最后总结一下老师的笔记:/ ]) T4 Z8 _% U5 L+ _* }. d6 \

2 h1 U' \. l/ r( j1 O& c" |为了使设备支持异步通知机制,驱动程序中涉及以下3项工作:
0 K& e6 V* z+ `1. 支持F_SETOWN命令,能在这个控制命令处理中设置filp->f_owner为对应进程ID。5 j+ s, i& X& X
   不过此项工作已由内核完成,设备驱动无须处理。3 s1 m$ K$ z+ t( A) d! X% U3 N
2. 支持F_SETFL命令的处理,每当FASYNC标志改变时,驱动程序中的fasync()函数将得以执行。
* J% d+ f/ r' }! e/ I8 a   驱动中应该实现fasync()函数。" ~3 k4 H7 q0 Q0 `5 v) [- u
3. 在设备资源可获得时,调用kill_fasync()函数激发相应的信号) @5 m2 D4 M, K) Z6 ?# k$ o9 ~% f
% @& t! J: N$ k& k7 n8 o* c7 S
应用程序:
0 B; _/ m4 c5 I2 ^5 \0 {4 @! Ofcntl(fd, F_SETOWN, getpid());  // 告诉内核,发给谁
/ M; l5 R  S6 x4 V% _8 c+ b9 d! C8 W7 O0 m3 _, D% a8 X' I
Oflags = fcntl(fd, F_GETFL);   5 k/ g0 ^) k' r2 \0 J; N4 ~2 q
fcntl(fd, F_SETFL, Oflags | FASYNC);  // 改变fasync标记,最终会调用到驱动的faync > fasync_helper:初始化/释放fasync_struct2 H1 V1 O2 M1 O: L4 p& R! v# \

0 ~* \' J9 b9 q) p
" i! u4 h. [  S$ G; m. h' d% t
4 W4 @. R: G% N0 b- l0 k/ N, A

该用户从未签到

2#
发表于 2020-6-9 16:08 | 只看该作者
竞争神经网络与SOM神经网络详解与matlab实践
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-11-25 21:15 , Processed in 0.171875 second(s), 24 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表