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

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

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
在上一节里,我们在中断的基础上添加poll机制来实现有数据的时候就去读,没数据的时候,自己规定一个时间,如果还没有数据,就表示超时时间。在此以前,我们都是让应用程序主动去读,那有没有一种情况,当驱动程序有数据时,主动去告诉应用程序,告诉它,有数据了,你赶紧来读吧。答案当然是有的,这种情况在linux里的专业术语就叫异步通知。
# V/ w& D* u- Z
* K. j5 h4 _0 b3 a. h0 s0 s上一节文章:
9 z- j, T! K8 N7 G* ^, ^) H
3 p, ]# T& l! ~: E
/ D# v; u, r9 W. v
在这一节里,我们将在上一节的基础上修改驱动,将其修改为有异步通知功能的按键驱动,目标:按下按键时,驱动主动去通知应用程序。! s7 w! e7 e, q' E
# U' [. Q6 V; x, f
问:如何实现异步通知,有哪些要素?7 j# x3 v; H: }3 M' G

4 p8 Z. [7 ^) i( G7 Q; Z答:有四个要素:
  I/ x+ V* {: V2 o8 L' e  H' `( X- Z8 ?+ }  g" U& r
一、应用程序要实现有:注册信号处理函数,使用signal函数/ j  y4 o+ _" c  o+ y$ a0 j

- i' h, q: l/ j; `二、谁来发?驱动来发, h1 Q9 \( `" Q. H' y

! v5 y/ }7 t3 c5 R三、发给谁?发给应用程序,但应用程序必须告诉驱动PID- F2 [: }$ c- j8 k$ r
8 Y. i7 R: G, f% ^$ H
四、怎么发?驱动程序使用kill_fasync函数
) s2 h, |  Y/ X( L- h5 _5 o2 _9 ]9 e" b) o" ]
问:应该在驱动的哪里调用kill_fasync函数?
. l$ C/ Q; c4 M. q* R; R2 Y' u8 B2 `( M/ e3 ?
答:kill_fasync函数的作用是,当有数据时去通知应用程序,理所当然的应该在用户终端处理函数里调用。4 u8 z& U2 \* _

) v3 J" i& ]4 ?0 l1 U8 Z! @' [问:file_operations需要添加什么函数指针成员吗?
( s+ W  w' O6 r* y2 n3 f1 ]! q0 e" o4 F: _- W/ A5 ?
答:要的,需要添加fasync函数指针,要实现这个函数指针,幸运的是,这个函数仅仅调用了fasync_helper函数,而且这个函数是内核帮我们实现好了,驱动工程师不用修改,fasync_helper函数的作用是初始化/释放fasync_struct
3 v7 A4 T( s$ G' Y* l8 @; S; {( d+ O; h+ v, [$ `
5 c/ J/ V2 E6 o. g! @4 a

" a/ g  Y! k2 m* A' r详细请参考驱动源码:5 |& U% S, b- h  N

4 r! a. q, a9 G6 B* i0 k, U$ D% w8 i: V
7 E* U3 a0 l0 I#include <linux/kernel.h>8 U- c& t5 V1 c1 Q
#include <linux/fs.h>
5 {: t+ K+ x  M, |0 d; w#include <linux/init.h>
) t& Y0 K3 c* x4 D8 F  I#include <linux/delay.h>
0 j9 R* @4 U7 P8 M3 _# h( S# G#include <linux/irq.h>6 W9 _3 D2 U* m6 @  ^
#include <asm/uaccess.h>
) v7 Z4 x1 ^/ U2 B& n+ m+ P#include <asm/irq.h>; J, T, r. F2 h+ ]$ T* J, c! g+ F
#include <asm/io.h>) a  ^  z! R$ e# t) O1 o1 s
#include <linux/module.h>- y6 [2 z' {- ~! L/ [
#include <linux/device.h>                 //class_create6 d. v$ L. f' d; N# D8 H  Z
#include <mach/regs-gpio.h>                //S3C2410_GPF1
1 Z! S* R8 D/ `0 t* D9 N0 A* ~//#include <asm/arch/regs-gpio.h>  
5 J. y6 B9 B* |) `#include <mach/hardware.h>7 ]5 \, Z, ]. V% ~9 I
//#include <asm/hardware.h>
1 {$ A5 @! @- J, S' M! f% O) Q/ W#include <linux/interrupt.h>  //wait_event_interruptible
4 i$ A6 x* V2 i2 V: n- Y3 G#include <linux/poll.h>   //poll& p6 U3 i* ]2 A& t# R
#include <linux/fcntl.h>
) j: y  B/ e% K5 {- q+ f0 |
1 D; L; q) M# x4 a2 t$ K& c( l" n8 N. t" U0 ?1 h4 _
/* 定义并初始化等待队列头 */
6 r7 E. m. l' M/ o) s! e) p) U% xstatic DECLARE_WAIT_QUEUE_HEAD(button_waitq);! [, q0 \4 {5 I! A

, e; ]: O+ b8 v
9 b7 [2 U! N: cstatic struct class *fifthdrv_class;
1 A+ i% }  u& h) gstatic struct device *fifthdrv_device;, U2 @$ m0 a* A2 t& ~; D3 ]6 K" _
, k' G& p, P0 T; J* U# Y# l
static struct pin_desc{
0 X% g/ L2 r5 p3 H+ \        unsigned int pin;, Y: `- R# e# ^8 Z9 E7 `
        unsigned int key_val;
- A& f0 Z$ G. M" H# k};
. Y/ Q8 O* m: a# H' @% x* N, ~) Z+ D7 R' G
static struct pin_desc pins_desc[4] = {' o; }8 j1 o/ a* T
                {S3C2410_GPF1,0x01},
; j3 o, u) }! o( p                {S3C2410_GPF4,0x02},
1 n1 x  I7 X" Q" ]( m3 E9 n                {S3C2410_GPF2,0x03},
' x$ B% f! R0 a6 i( r                {S3C2410_GPF0,0x04},
; A. ^( d: l7 m& [& ~3 S! A; i7 V- z}; 4 w' V! N9 w4 y8 k; D
6 A+ a" H1 r% `! d) k7 T
static int ev_press = 0;: b- Z# _& m+ L) H
" x* B) b* E$ Z9 C1 H" N
/* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */
) R& N3 M1 `4 J/* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */
: l4 Z) X! S% i7 Q, ]* X/ astatic unsigned char key_val;2 @$ ]6 W* U5 i
int major;
2 r' M; T& G, M* u  C4 J" F$ M9 h! E5 y7 {3 v, k0 f
static struct fasync_struct *button_fasync;$ I' }( B& D7 z. v$ G
9 }! M4 T- N4 |- P$ H
/* 用户中断处理函数 */% @8 e# a1 o  x+ |2 _
static irqreturn_t buttons_irq(int irq, void *dev_id)
' k/ G6 q- b: T+ r$ G{
# S) U  x( D: x        struct pin_desc *pindesc = (struct pin_desc *)dev_id;, O% H9 k) Y# p/ @! P' a8 e
        unsigned int pinval;4 p& K8 j, Y: B/ {1 Q( x, G3 V
        pinval = s3c2410_gpio_getpin(pindesc->pin);
" G$ K2 y% T) L( ]. E# Y
/ b* |& S' B3 N% x7 e1 U0 D. F        if(pinval)
6 c1 r+ t, z. D, @        {
! O2 I- D- q+ L6 [                /* 松开 */
- S$ R$ ]* M+ B$ s! U4 Z( J6 U                key_val = 0x80 | (pindesc->key_val);
* x6 W  z3 k( D$ a2 J$ ^  N        }0 H& e* R! B' T
        else
: Q2 J3 F& z, x* Q        {( S" ^' y: C6 q8 C# ?# t
                /* 按下 */
2 F; u* R+ V2 V, ]1 O                key_val = pindesc->key_val;+ b" g% M5 B' D
        }/ E0 ]1 @1 }' g4 Z9 s. F, B4 @
' J3 _, O: u' A2 v" W
        ev_press = 1;                                                         /* 表示中断已经发生 */
5 `: R( C  x2 _8 [* u$ H, t        wake_up_interruptible(&button_waitq);   /* 唤醒休眠的进程 */4 D3 a* g7 N) v* d& p6 n( s
$ D  t" @: C% l* R" V. G: g
        /* 用kill_fasync函数告诉应用程序,有数据可读了
- y0 x( h) ?3 i4 n         * button_fasync结构体里包含了发给谁(PID指定)/ D  I; }) [1 T5 v. b
         * SIGIO表示要发送的信号类型
0 c% H' m! R$ Q  X         * POLL_IN表示发送的原因(有数据可读了)
+ `4 N: ~* D) I, Y% Q  i5 x* j( q9 B         */
" v! ^9 s) L! Y9 u" Q% t9 n        kill_fasync(&button_fasync, SIGIO, POLL_IN);
3 P( ~, r- @! O9 ?) L6 ~6 M        return IRQ_HANDLED;. \: V+ i2 V: A8 i% Y* X
}6 x) V4 Z6 A5 e. \; B
static int fifth_drv_open(struct inode * inode, struct file * filp)+ [0 N# q$ _! G/ T' x
{) K# w, m( Y4 y/ a+ H1 i, [3 Z
        /*  K1 ---- EINT1,K2 ---- EINT4,K3 ---- EINT2,K4 ---- EINT0
: V2 V+ I, w. y. w3 A3 i           *  配置GPF1、GPF4、GPF2、GPF0为相应的外部中断引脚
* z% ~! r3 v1 K' `6 W( x+ y           *  IRQT_BOTHEDGE应该改为IRQ_TYPE_EDGE_BOTH4 A- s' [# L1 n6 |% @0 f0 U7 ]7 c& \
         */
( t' @0 a9 y% a4 k! `8 B+ @0 B8 @        request_irq(IRQ_EINT1, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K1",&pins_desc[0]);
8 }* h) r% [- g. z* p        request_irq(IRQ_EINT4, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K2",&pins_desc[1]);/ \2 U! h+ B7 M6 B& I$ S
        request_irq(IRQ_EINT2, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K3",&pins_desc[2]);
/ A0 Z, o2 ?! {( v4 \        request_irq(IRQ_EINT0, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K4",&pins_desc[3]);
0 l3 i. }, }7 n3 k        return 0;) a6 e4 T  I$ M+ G: j4 n3 r8 W
}5 ]1 T* ~9 o6 M* h+ b/ i' L

5 V/ L, o6 y  R* G( O0 Z  istatic ssize_t fifth_drv_read(struct file *file, char __user *user, size_t size,loff_t *ppos)
: u. ]$ Q. A" I4 Z: A{
: R! e: Q" e: j6 |8 J8 o        if (size != 1)
' ?; B9 S8 X. N' j( @                        return -EINVAL;
) B( h  E/ n" C0 d# R       
! f# m3 ]* O  K" }        /* 当没有按键按下时,休眠。2 L; H; g2 N5 ?3 o
         * 即ev_press = 0;
; G; F( _% |. c0 |3 e: Z* R8 `4 A         * 当有按键按下时,发生中断,在中断处理函数会唤醒$ G$ F# J: n; Z& z5 p1 C* Y) t
         * 即ev_press = 1; , E6 }, Y! ?, U) f
         * 唤醒后,接着继续将数据通过copy_to_user函数传递给应用程序
) a! T! m9 p1 o) \" t9 S         */
3 x( _: t' G9 `# b; n) s        wait_event_interruptible(button_waitq, ev_press);
' W% t% R+ J0 H. e% {8 k' O2 ?& w* ^        copy_to_user(user, &key_val, 1);
$ r& A. _9 @# k* \5 H7 s, Q       
5 m) L2 E9 i) h! z$ C0 R5 K        /* 将ev_press清零 */
, C3 E3 N( D: u4 u9 O. A        ev_press = 0;( e% o, V7 x* n" O7 M: R! K  x' {
        return 1;       
- d, [! L1 x+ _' y/ S% v+ H$ I}
3 `+ c/ N( M3 {4 w! N0 ~( y0 o2 L* z/ ]* s
static int fifth_drv_close(struct inode *inode, struct file *file)
: s  v7 l( k" |4 b2 ^{8 c8 e' g# Z% ?
        free_irq(IRQ_EINT1,&pins_desc[0]);' N" m+ R* X( t5 P& O6 n
        free_irq(IRQ_EINT4,&pins_desc[1]);
4 x- J. ~5 [. E$ J0 v! l/ L        free_irq(IRQ_EINT2,&pins_desc[2]);
9 l. }4 m6 m7 p9 b        free_irq(IRQ_EINT0,&pins_desc[3]);
" K: Y, q( c0 E4 }% k        return 0;- A% l- X0 o4 e8 F0 Y8 v/ y
}
- ^6 I0 O8 P5 P6 y+ p+ x
8 x. [3 b6 k: O/ n) G* a& a3 Mstatic unsigned int fifth_drv_poll(struct file *file, poll_table *wait)
7 z8 u4 t3 U2 M3 \. Y{
* m1 h/ a! |- Q- I/ ~  q1 G        unsigned int mask = 0;( d, z+ F5 {5 r6 S3 S4 i
* }* D1 E5 s, R- \4 i
        /* 该函数,只是将进程挂在button_waitq队列上,而不是立即休眠 */
( `9 v# T+ e3 j7 h; @( W        poll_wait(file, &button_waitq, wait);* i: H. R' q& Q% G

; i2 h) a6 c, Q( y% k7 q        /* 当没有按键按下时,即不会进入按键中断处理函数,此时ev_press = 0 4 q/ v6 B5 b" B$ F8 i$ J
         * 当按键按下时,就会进入按键中断处理函数,此时ev_press被设置为1
/ z2 E  U7 s- b( n+ G. g, c- h9 G- ^; _         */& I  o& @( s9 Y& x3 x* N
        if(ev_press)8 ~6 H2 I$ |6 {: l; W: `
        {3 V" P7 `$ c$ j
                mask |= POLLIN | POLLRDNORM;  /* 表示有数据可读 */
/ U. P2 x" ]' a% ]8 U        }  {; [8 V6 G5 x# t5 p
4 H, j! a; U0 s4 F
        /* 如果有按键按下时,mask |= POLLIN | POLLRDNORM,否则mask = 0 */
0 z; D/ U. E7 d4 g        return mask;  ' i8 t* Z. _9 K
}+ r0 |3 K' o% O' s

0 X& M! j, H' O7 |) d8 ?# x/* 当应用程序调用了fcntl(fd, F_SETFL, Oflags | FASYNC);
  y9 C# h8 v3 w5 A8 e * 则最终会调用驱动的fasync函数,在这里则是fifth_drv_fasync
0 u4 H3 ~8 l* m5 H# } * fifth_drv_fasync最终又会调用到驱动的fasync_helper函数
% A& b$ G1 A3 v5 e * fasync_helper函数的作用是初始化/释放fasync_struct, C4 V% G- k% u
*/
' T8 k& n( _6 z# j; d2 E) dstatic int fifth_drv_fasync(int fd, struct file *filp, int on)
( P8 b2 j& L8 Q2 K. o& A{
3 @  W8 J. I/ P4 w( R; l, S7 y        return fasync_helper(fd, filp, on, &button_fasync);
7 k! U+ Q0 E& K5 @& D- N}5 n* s) ?" P. \
: d- T0 U, L- |
/* File operations struct for character device */( T, o/ V/ ?$ r" a% ?
static const struct file_operations fifth_drv_fops = {1 G1 f7 X$ p: J7 H
        .owner                = THIS_MODULE,' @- H" I1 g7 p' I4 U/ S; P3 O
        .open                = fifth_drv_open,  W( {! M. |' X/ [! Y, f; l
        .read                = fifth_drv_read,
5 H. w* N' c! }8 t        .release    = fifth_drv_close,5 c$ X$ [- J( {
        .poll       = fifth_drv_poll,
1 |, E6 i" a3 `6 S7 A! O& b' }        .fasync                = fifth_drv_fasync,
  W) u, u0 }5 ~4 ]+ L9 r- Z};0 G! t$ A' m; g5 ?

' Z6 O& U! S0 |, N: M# o# h* @
' Q  y5 j  S# c# g! a/* 驱动入口函数 */! f8 L9 A! n6 F) g" D" [* Z
static int fifth_drv_init(void)
  u6 `' J& `2 b9 D- R2 G7 c7 {{+ _; L4 g) ^8 s. U5 y( T/ c
        /* 主设备号设置为0表示由系统自动分配主设备号 */+ W4 ?/ \( C" f) Z. `
        major = register_chrdev(0, "fifth_drv", &fifth_drv_fops);7 F  q. X/ A( I6 e' E1 ^* W

+ g% Y( Q0 ~/ t* a        /* 创建fifthdrv类 */) X: e2 I' h2 o0 S: p7 e
        fifthdrv_class = class_create(THIS_MODULE, "fifthdrv");: E  K. `$ J1 s  ]
& z8 l  O9 g0 |3 b  x
        /* 在fifthdrv类下创建buttons设备,供应用程序打开设备*/# x- L% H, H+ x* }8 \
        fifthdrv_device = device_create(fifthdrv_class, NULL, MKDEV(major, 0), NULL, "buttons");+ O9 d9 Y. G# H( [& l

6 D8 z- c: ?; u4 m        return 0;5 L2 [" y5 k, m, o
}
6 }( u4 \& B. w: h" ?+ n: L" L
0 m3 s" Z5 \: a3 b- H3 D/* 驱动出口函数 */1 _* p1 k1 V- F% ~2 P) k4 b' V6 w
static void fifth_drv_exit(void)
$ y* q! T# `7 j{
, V5 p" e7 ^  I2 ~  |        unregister_chrdev(major, "fifth_drv");
- |; Q/ P4 A+ E$ q  R) d$ X! `        device_unregister(fifthdrv_device);  //卸载类下的设备* |0 f" O& O' P
        class_destroy(fifthdrv_class);                //卸载类
) G2 o5 \2 k  w- E}
) g6 S/ }0 R, o4 e8 q+ M
9 W: k& }, b4 Q3 t5 c' L1 r* @module_init(fifth_drv_init);  //用于修饰入口函数
1 x  J: L; U; E6 ^module_exit(fifth_drv_exit);  //用于修饰出口函数       
7 {( N) ~. \" `- R* L! Z. r; u
8 |9 `+ [! m- D8 ^MODULE_AUTHOR("LWJ");4 h3 l4 j: [" i) r
MODULE_DESCRIPTION("Just for Demon");) E8 J/ Z1 t8 ~2 b
MODULE_LICENSE("GPL");  //遵循GPL协议3 G/ L* b' W# g
7 d0 G, x2 H7 H3 ?) D" U
应用测试程序源码:
  ~7 A  A" G0 i2 M
1 v: h) g7 ?) _4 a#include <stdio.h>* H  C7 Q& P- s8 E: D
#include <sys/types.h>& A) \) Z( `" w2 u
#include <sys/stat.h>
" B" ?- h6 B0 U#include <fcntl.h>/ \( ~( Q# W1 X0 S3 z
#include <unistd.h>        //sleep
  v" F8 d. l- k  o8 t+ N2 Q#include <poll.h>: [2 k. ?) n* P5 s4 f- r
#include <signal.h>! d6 p1 F4 |9 n1 H- E% c$ r
#include <fcntl.h>
6 R: ]+ k" `7 `( S0 z. r
# B' _9 P9 g  p9 hint fd;% t* E, I, ?  G4 d
! d2 m& {+ ~+ e) u6 b  n* o5 j
void mysignal_fun(int signum)& U& V" v% D  o% p5 z
{, Z3 t9 f, o* o2 J% ~0 v% H# k
        unsigned char key_val;; M% x% ^( j- Y! h) ~, n
        read(fd,&key_val,1);
# I  N2 H3 E3 q+ V: E        printf("key_val = 0x%x\n",key_val);% a1 ?# B; u. n" x- j4 l
}
" R* N% x" o5 M* Y! z$ P0 m9 R) P+ ^: M' B# l4 K  M* t- I. K. ^
. [; e" H: Z0 \# m) w" P( K' y) q
/* fifth_test
* ]$ c/ ~9 G3 V! [' v. n */
) \  g; A% b9 Y+ lint main(int argc ,char *argv[])
) H5 N, c; D/ m# S3 H{
. b" u! Z7 o0 B! A; u: ^        int flag;
4 d+ y  Z/ t2 O1 Y2 W# c# q        signal(SIGIO,mysignal_fun);
- L% @) i$ I1 E# Z7 t8 m3 c! D/ Q9 p
# J0 W! O; ]1 v, |  o$ ^4 o        fd = open("/dev/buttons",O_RDWR);( q" u1 I/ U. p. ?8 i: b; S. G
        if (fd < 0)
3 F& C  l/ z( F8 d6 b; \" O" S        {
) x. ]1 g4 t% [; i3 ?; u                printf("open error\n");. X2 t& G9 n- |0 D6 X
        }
* b' x: Q4 K, _( \8 B5 v$ ]
  w% [* i1 \  ~) q0 \        /* F_SETOWN:  Set the process ID/ g* o/ ~1 e* `5 e& o
         *  告诉内核,发给谁
' p7 S& v+ E  L5 _! C( k         */
7 D: m1 O( z" e$ |        fcntl(fd, F_SETOWN, getpid());
& l4 v( H' J$ v' K7 D; i4 b5 z" B- p& }4 Z
        /*  F_GETFL :Read the file status flags" T8 y2 E2 Z9 d# V# L
         *  读出当前文件的状态
% G( m- L6 v% |, Y  m0 t6 d         */" U" F+ `" F% P, v1 q
        flag = fcntl(fd,F_GETFL);) P; c+ n, ~1 l+ d  ~. c
1 V; Z, `1 K+ _) ~
        /* F_SETFL: Set the file status flags to the value specified by arg
- y0 k: r# J0 S+ S* ?         * int fcntl(int fd, int cmd, long arg);; J  h. u2 n8 ]6 d6 k# ^+ d
         * 修改当前文件的状态,添加异步通知功能
# t) r4 O4 g& O         */
3 {5 b' O# P3 }6 ?8 N$ M- r1 G# N( ]        fcntl(fd,F_SETFL,flag | FASYNC);$ n  J' r( y1 ~( F# v3 J% z: \3 o
        ( e7 K$ `+ H- s2 S- |
        while(1)
! h1 d( ^5 Q* W        {
) _7 ]/ x9 W- u2 A/ E/ _( ^                /* 为了测试,主函数里,什么也不做 */
3 g. K2 Q$ X  Y% Z: O* u) ]                sleep(1000);6 J  r5 |( p* E# P6 @
        }, r" L( L/ N4 ~& ^9 C) X
        return 0;$ Y! x; ^; l( x4 R9 M- o$ g& g6 D
}
) o; f) \  H% R/ `0 c* ^- {3 x/ \  c3 A, d5 p* H; z2 q: G
测试步骤:
, p* ]6 I" c4 Y& f  k
- F+ H  I5 e  M' H& g! y[WJ2440]# ls 5 G$ |9 {, n! p+ K( \
Qt             fifth_drv.ko   lib            sddisk         udisk8 z1 Z( L5 U7 k1 _/ W2 c' w' k" j
TQLedtest      fifth_test     linuxrc        second_drv.ko  usr
" c( n$ w# _3 b: L  Zapp_test       first_drv.ko   mnt            second_test    var3 l2 h2 t2 l+ V7 n
bin            first_test     opt            sys            web
+ ]  S' F* Y2 P2 ndev            fourth_drv.ko  proc           third_drv.ko7 H  T0 s7 H8 Y( r7 W( U3 G' i
driver_test    fourth_test    root           third_test
5 d6 U8 n2 z' Q: f( cetc            home           sbin           tmp
9 H6 f  e$ r0 O) F  U' G+ i[WJ2440]# insmod fifth_drv.ko
4 z5 |$ I' r5 [: K+ t[WJ2440]# lsmod
) w  W2 [) u) h  |. u( Y: Dfifth_drv 3360 0 - Live 0xbf006000
( @% [$ a0 `4 v4 v  [7 `1 i' G[WJ2440]# ls /dev/buttons -l
) j3 p+ U& |( Acrw-rw----    1 root     root      252,   0 Jan  2 04:27 /dev/buttons$ d2 U5 G4 y' B, ]5 k
[WJ2440]# ./fifth_test
$ ]( n& _$ f! M3 hkey_val = 0x1
! ?$ P0 L4 V2 O0 D/ ckey_val = 0x81
8 c) X5 l' J* s7 Rkey_val = 0x4
" [0 {$ G- V! @$ \% \/ T# {key_val = 0x84
5 m. p7 Q& n8 w- b/ k% i5 hkey_val = 0x2! G: U2 f" q2 m- P- b* ]# A" z
key_val = 0x82
. }2 b" `9 }+ Z8 P$ _/ ]% X: @key_val = 0x3  s  B% G! L. u
key_val = 0x83
, N' @  W! E: B; H+ s2 q% a2 Y( wkey_val = 0x41 Z, U, P! v8 `+ E
key_val = 0x84* f1 w# A; N( _) N. n2 P4 U9 g
key_val = 0x84
# M$ S' D' @& t/ [; \' D7 A% H9 p( w' X$ T$ v! Z
由测试可知,当无按键按下时,应用测试程序一直在sleep,当有按键按下时,signal会被调用,最终会调用mysignal_fun,在此函数里read(fd,&key_val,1);会去读出按键值,这样一来,应用程序就相当于不用主动去读数据了,每当驱动里有数据时,就会告诉应用程序有数据了,你该去读数据了,此时read函数才会被调用。
+ E+ o" \' r; h2 k" e: n0 ]# L; o( k; S6 n9 R

; m# f0 A$ v4 m/ S9 a: o这里最后总结一下老师的笔记:7 N$ t) K, \' \+ ~. c0 b; d

- E7 A4 O1 I8 q' w& U& O) G为了使设备支持异步通知机制,驱动程序中涉及以下3项工作:
5 a: t) ?, R! a* |3 y1. 支持F_SETOWN命令,能在这个控制命令处理中设置filp->f_owner为对应进程ID。
; A- h) {/ E% v' ^/ [   不过此项工作已由内核完成,设备驱动无须处理。) P, I! c5 ]; n. [+ e) O
2. 支持F_SETFL命令的处理,每当FASYNC标志改变时,驱动程序中的fasync()函数将得以执行。# h1 m6 [! n1 r- s
   驱动中应该实现fasync()函数。
8 n4 j' a) u7 y1 T& t6 r* S3. 在设备资源可获得时,调用kill_fasync()函数激发相应的信号
. t1 ~1 h" |8 S
' g" i$ W! N0 t5 j应用程序:
; Y& \8 z4 P7 q+ w& m2 [fcntl(fd, F_SETOWN, getpid());  // 告诉内核,发给谁
% P0 o9 H' `- b0 _' ]
: X; y* L/ k+ `) ]$ X9 `Oflags = fcntl(fd, F_GETFL);   
  S; J- A% f' V6 |0 Jfcntl(fd, F_SETFL, Oflags | FASYNC);  // 改变fasync标记,最终会调用到驱动的faync > fasync_helper:初始化/释放fasync_struct
: _) o' F4 V5 {7 Y9 }9 p
2 G  Z$ Q, _3 S, ?+ s" T; O$ R) b$ z/ b" d/ p

4 t* G; ]# F" v0 C' r: h

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-6-30 03:15 , Processed in 0.093750 second(s), 23 queries , Gzip On.

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

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

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