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

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

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
在上一节里,我们在中断的基础上添加poll机制来实现有数据的时候就去读,没数据的时候,自己规定一个时间,如果还没有数据,就表示超时时间。在此以前,我们都是让应用程序主动去读,那有没有一种情况,当驱动程序有数据时,主动去告诉应用程序,告诉它,有数据了,你赶紧来读吧。答案当然是有的,这种情况在linux里的专业术语就叫异步通知。
  d( V7 @: q0 [) A1 y) m) w4 m& R6 ^& X; ^9 ]
上一节文章:
7 I' ?% C) R! C6 J( A
8 a, V7 _9 F, N( R

% M6 K) w" F4 O) I, R+ f! q在这一节里,我们将在上一节的基础上修改驱动,将其修改为有异步通知功能的按键驱动,目标:按下按键时,驱动主动去通知应用程序。/ |) n3 v- I! t  H& E# q
1 M4 o2 T# D( Q! D8 U3 M: d
问:如何实现异步通知,有哪些要素?
/ G+ F# U% |: r' U, @' ?5 k! W9 U7 x
答:有四个要素:7 S7 e/ g4 R& ?# p$ N) o/ ^; X

0 B* C; Q% A- ~$ J* H一、应用程序要实现有:注册信号处理函数,使用signal函数/ a! R; \; c6 J6 j( v' S) ]: ^' m$ d

+ D3 f0 U5 e" H* o9 a- E二、谁来发?驱动来发$ y+ }% m6 @* [% d: j

0 P) e6 X2 Z& {) o三、发给谁?发给应用程序,但应用程序必须告诉驱动PID
) k- h" O$ d2 Y/ o  X5 @- v  [/ R
四、怎么发?驱动程序使用kill_fasync函数
* ~+ l& V  R$ ]  K$ U- {" z' [2 B! N6 w8 u" I9 q
问:应该在驱动的哪里调用kill_fasync函数?' U( r! S3 U; [  `2 q9 P
  `7 g$ W0 {* D) I/ j
答:kill_fasync函数的作用是,当有数据时去通知应用程序,理所当然的应该在用户终端处理函数里调用。- z- R2 N/ O/ Y* ^* [1 b; S

: q, A1 H+ m& G问:file_operations需要添加什么函数指针成员吗?
( O7 I& Q6 A/ t6 U. J
  s9 d! [4 d8 O) S! E4 J( R答:要的,需要添加fasync函数指针,要实现这个函数指针,幸运的是,这个函数仅仅调用了fasync_helper函数,而且这个函数是内核帮我们实现好了,驱动工程师不用修改,fasync_helper函数的作用是初始化/释放fasync_struct
$ T  N, C9 a( m+ |; O4 J) H6 L& |& E% C- c/ j0 \$ A
" r5 m9 C$ W( D

; j7 n- V0 r0 G, C+ s1 r详细请参考驱动源码:( Q5 t. z; a9 L/ H" U7 O

4 f  }6 W$ O2 T! V: ]
* a: q5 J0 E; L& |#include <linux/kernel.h>
! C1 S7 d' ^3 l/ {5 U  t' A0 l$ N1 E#include <linux/fs.h>) V' Q0 t  s5 X! ?% S( K% I5 Z- H5 X, O% l
#include <linux/init.h>
+ I1 I( ?' r8 [5 {! N& o9 U, c#include <linux/delay.h>
: ?6 @- I, N) _. I) p: d#include <linux/irq.h>
, c" G  E+ F8 C" `#include <asm/uaccess.h>
' X6 ^* S2 G9 S#include <asm/irq.h>. ?2 E. u* s, u1 h6 |$ }9 V& u
#include <asm/io.h>
  z: o; h/ z) ?2 G' w) ^+ U#include <linux/module.h>
! U# F  w1 r& W/ c* H9 l2 |#include <linux/device.h>                 //class_create
/ _7 C4 p* Z5 m' S  v1 ^#include <mach/regs-gpio.h>                //S3C2410_GPF1
# L1 t, K9 \1 n: C9 j# e//#include <asm/arch/regs-gpio.h>  
& h( H* @& c) y5 b. \' C#include <mach/hardware.h>
( U/ D$ Y2 S" R& i% `' [, ~4 c//#include <asm/hardware.h>
4 x. z. A$ Z! N2 k: N0 K; S* a( C#include <linux/interrupt.h>  //wait_event_interruptible" a( E' w  i6 i3 Y, }7 p: f9 }( V: _
#include <linux/poll.h>   //poll- K% ]; m' f$ y' z2 u1 ~
#include <linux/fcntl.h>/ V1 r# E$ r5 q" r' g
% P) P$ K( |4 O
2 F3 F: \% N: {, }# H
/* 定义并初始化等待队列头 */4 T) _; ]! z, K
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
. L4 Z" \" V( r1 r; q  c
" `. }3 Y% l6 [  K  J7 I4 T
  k0 `8 c, W# a+ N) }static struct class *fifthdrv_class;
: B, L- N  r* D+ _static struct device *fifthdrv_device;
" n- B% t6 h" G9 A6 @! }- B! v* t9 T- ~# K- ^9 L
static struct pin_desc{
4 A$ M6 @6 k- g$ x' b9 w        unsigned int pin;- B' A, ?- @4 U
        unsigned int key_val;
. B. X! G; K$ r; p8 {) ^6 ~};- L# r/ p8 V4 n2 A4 k2 E7 t
% [) ?9 T8 c+ r6 y' ~6 H; G; ]: d# X
static struct pin_desc pins_desc[4] = {+ M' W7 @( B  T. U8 D5 F; J! ^
                {S3C2410_GPF1,0x01},+ D' n, e3 m* A1 e, V
                {S3C2410_GPF4,0x02},; x. s( g& s! X
                {S3C2410_GPF2,0x03},6 Q" e. c. S! F
                {S3C2410_GPF0,0x04},
* y" p4 [- L: S; H# e! p! ]};
+ o- [+ @0 s* H: \: a- Z; n$ m
; j; |  x: r4 |* _static int ev_press = 0;
6 \. \7 |; Q3 J, l- W1 Y( B/ e( S* _+ |  t; l  n; I
/* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */
, i% k* D$ Z5 n+ M) |. o" A/* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */& R5 u, x# i# d2 u7 {1 C0 a
static unsigned char key_val;
  _+ i; b6 a* j* Y# D! K  ~int major;
# Z" J7 }* z7 T7 a: f4 \5 _. S+ T3 l9 A1 f; r+ m
static struct fasync_struct *button_fasync;
' G$ \, J% G# Q, ?) w- Q5 s) F" H. E+ L
/* 用户中断处理函数 */
' n2 p9 a" q: C3 O: V: }static irqreturn_t buttons_irq(int irq, void *dev_id)
- D9 D9 A8 c$ U( @{7 n8 U- M' G( P$ O$ J. e: }
        struct pin_desc *pindesc = (struct pin_desc *)dev_id;" _4 K$ f$ e; @1 T
        unsigned int pinval;; d$ x  x8 ~  y+ w; z& }7 p
        pinval = s3c2410_gpio_getpin(pindesc->pin);
& \9 u6 t3 @; R: j6 v# Z2 T
. |. \( V' m( W        if(pinval)
- \4 W' t; }7 I5 D        {
8 q  M( a4 O& N1 b0 s( v9 ?3 A! R5 `                /* 松开 */' Z) G5 w1 i5 z. A- T
                key_val = 0x80 | (pindesc->key_val);) Z$ Z; k# m' ]8 C* |* v
        }/ d# i  q9 w# q: \0 L. Q
        else! L  x' D. A: c! g6 @
        {* I1 s# j" }6 [: Q0 R, ~* v0 y
                /* 按下 */
/ {  v6 l! Q: d2 ~$ D" o                key_val = pindesc->key_val;
) v# ?6 z. {' Q: a$ J6 Q        }+ L+ A0 ?; o/ Q+ {0 ~/ n

4 M1 N3 k  z1 p# E# K        ev_press = 1;                                                         /* 表示中断已经发生 */
3 z/ T" A/ H5 d        wake_up_interruptible(&button_waitq);   /* 唤醒休眠的进程 */. S, t' y+ ?' e8 a! w

/ U6 o# t. ^, }2 k' l' \  a        /* 用kill_fasync函数告诉应用程序,有数据可读了
$ q; g2 ^0 L6 d2 V$ n( X; b         * button_fasync结构体里包含了发给谁(PID指定)
' Y+ Q9 D( i/ h         * SIGIO表示要发送的信号类型
6 k  Y- P) f8 A% m7 F9 z: U- Q+ r; R         * POLL_IN表示发送的原因(有数据可读了)
1 }. Q' G! i% l# t! e         */
; ^" _: f* Q4 _* V- b, f" |        kill_fasync(&button_fasync, SIGIO, POLL_IN);
& C) L2 c% b1 z7 s( N        return IRQ_HANDLED;
: V5 e  x) u, O5 m6 ?& H5 p1 W$ O}5 T* A* h( V6 n, n1 Y
static int fifth_drv_open(struct inode * inode, struct file * filp)
. e2 Z- n4 ^9 ?, m. @" ^; v& N{0 h0 g$ _0 Y: Z; x0 w
        /*  K1 ---- EINT1,K2 ---- EINT4,K3 ---- EINT2,K4 ---- EINT0
& Y) D) F8 z+ h1 ^           *  配置GPF1、GPF4、GPF2、GPF0为相应的外部中断引脚3 Z; s! |+ ^1 j# X
           *  IRQT_BOTHEDGE应该改为IRQ_TYPE_EDGE_BOTH$ ~+ K( j, o) _9 t2 \
         */
1 k; h$ v3 b+ c- S: Y        request_irq(IRQ_EINT1, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K1",&pins_desc[0]);
* z5 [% F: Q5 e. ~8 E( a. Z: d        request_irq(IRQ_EINT4, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K2",&pins_desc[1]);- }# G+ k, C% e* T2 V; L' U1 U$ ?' r
        request_irq(IRQ_EINT2, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K3",&pins_desc[2]);
5 y1 C7 P8 O" `1 S5 x/ P# @        request_irq(IRQ_EINT0, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K4",&pins_desc[3]);% a% v3 V6 E$ W# I, v$ S; s
        return 0;! r: M2 p/ ~# r! Q2 N' R
}
- \8 J0 m% _2 `5 M( a7 e2 n5 Y, k  L/ H$ g+ ~$ O9 W2 u1 L
static ssize_t fifth_drv_read(struct file *file, char __user *user, size_t size,loff_t *ppos)7 Y- F, T# X) j
{6 t3 h! c# m  L8 N" p. ?
        if (size != 1)! Z$ d/ E8 v% Z2 p
                        return -EINVAL;/ D- j7 ^4 R: [# x# ]
        & q: h3 C8 R0 |8 U& B. Y% o
        /* 当没有按键按下时,休眠。
8 l3 D7 f3 I' a* B5 [1 j; \; s         * 即ev_press = 0;
1 G0 `8 Y; N; i. y7 F; s         * 当有按键按下时,发生中断,在中断处理函数会唤醒7 b0 Z* t; m2 ]2 l# O2 j+ l$ X
         * 即ev_press = 1; 9 V  x0 R% a: N, \% e
         * 唤醒后,接着继续将数据通过copy_to_user函数传递给应用程序
7 t! v3 r  ~  }! [5 H) f4 q         */
. N, ]( T8 q( n0 y/ a        wait_event_interruptible(button_waitq, ev_press);
1 G% u: f' x: [- P+ E        copy_to_user(user, &key_val, 1);
$ P  w3 q3 D2 ?1 E) I! f  l3 i0 d        % l6 t# i1 y( x8 o; d$ @3 [3 ?& J
        /* 将ev_press清零 */# [( c2 G- ^3 t1 i+ V
        ev_press = 0;
0 \! J! D0 t) R- q        return 1;        6 s1 J4 W) ^' r" y! Q1 o$ d
}
' _5 A! Y3 U6 J# F) U- D$ m  q1 A: _) E- w
static int fifth_drv_close(struct inode *inode, struct file *file)- ^! a& j6 q$ r9 Z
{
& J! I$ c# x2 u8 C        free_irq(IRQ_EINT1,&pins_desc[0]);, X$ y6 {8 l  A7 c
        free_irq(IRQ_EINT4,&pins_desc[1]);) |; }( Q1 Y  Y* n
        free_irq(IRQ_EINT2,&pins_desc[2]);! e* {4 [* x( }, Q9 c( O4 f
        free_irq(IRQ_EINT0,&pins_desc[3]);7 F  Y4 h0 O* ~5 Z/ {6 Z7 i$ R5 z
        return 0;
+ W- P3 i2 f4 @+ C}7 ~" z( z* A6 H$ k" @

* X1 h& s/ I$ H& Y- k% Y& wstatic unsigned int fifth_drv_poll(struct file *file, poll_table *wait)$ p- V# D: U6 h
{
; [* D$ Z4 ~0 j9 z4 k- L9 e        unsigned int mask = 0;
4 U) P. z7 u- H. f, Q
/ P. C/ s' }5 n$ J5 B( j! o  E& t        /* 该函数,只是将进程挂在button_waitq队列上,而不是立即休眠 */
3 z: B: ^4 q  J" ?  c' [        poll_wait(file, &button_waitq, wait);2 r6 e! c! N; ~2 k6 L
/ v' U! F+ n# Z& b( E
        /* 当没有按键按下时,即不会进入按键中断处理函数,此时ev_press = 0
) R4 t) \# X; k+ h5 O' s         * 当按键按下时,就会进入按键中断处理函数,此时ev_press被设置为1/ x& ^  _/ x& E! a- C
         */: N1 h2 ?1 n' j
        if(ev_press)2 {* p# X0 J, |7 b3 E8 @/ r( S, j
        {7 X% M' y, l  l- Y2 G: w
                mask |= POLLIN | POLLRDNORM;  /* 表示有数据可读 */
. u. s# G4 }# k" @# V5 u9 {        }% @" H6 k. T% j, e, i0 T
( P0 e. v, Q, j0 b: }
        /* 如果有按键按下时,mask |= POLLIN | POLLRDNORM,否则mask = 0 */, ~9 m" z* Q3 T$ H* t2 c
        return mask;  
- N) I# s2 c9 |) q& J' [}/ F0 F2 a5 {; U  r
& |. f7 A$ e- V
/* 当应用程序调用了fcntl(fd, F_SETFL, Oflags | FASYNC);
  o# ]* B5 D. X0 M( C' ~) Z * 则最终会调用驱动的fasync函数,在这里则是fifth_drv_fasync# K8 l, \# x. H( q  c  e7 s
* fifth_drv_fasync最终又会调用到驱动的fasync_helper函数
0 b& G& r& t  V* a6 [* t0 @! s * fasync_helper函数的作用是初始化/释放fasync_struct1 W6 j0 g( p% J* ]/ o* [4 I1 V2 r  n
*/4 c% G5 M( u. `: U* M
static int fifth_drv_fasync(int fd, struct file *filp, int on)* }5 n$ v3 [% ?
{. q- g: \. }2 \5 d1 F0 Z  z/ P
        return fasync_helper(fd, filp, on, &button_fasync);3 A* Q" r6 O$ \. M
}# T0 s" o) h) f( c( {$ X  R# t
( r" I' Y" O9 r+ l! y5 L
/* File operations struct for character device */4 `/ t$ U) z1 n# K! \; q
static const struct file_operations fifth_drv_fops = {; Q5 T+ v$ z/ b. I( D
        .owner                = THIS_MODULE,/ \2 x, Z1 f! k
        .open                = fifth_drv_open,
3 Z+ `# y. `, {( I/ z  g7 i' X        .read                = fifth_drv_read,
% a6 O! y* x* t/ V/ i/ N) }4 g% E$ V        .release    = fifth_drv_close,6 t, h' O6 k: p( P' ?' h5 w4 {
        .poll       = fifth_drv_poll,0 z! E8 s2 ^* p1 s
        .fasync                = fifth_drv_fasync,3 f, O7 ]- i4 s  N6 m$ W! \; I7 H
};
, Z' \* ], h, f  `( l! I& y) _" {: g& A% N

( P- l/ C! ~5 f: [/* 驱动入口函数 */
1 n! ?* x# U) g# E9 t2 Jstatic int fifth_drv_init(void)  h; E6 p) {% w  x( e
{
+ e" H/ N9 N- D- f3 ?3 q  i  ?        /* 主设备号设置为0表示由系统自动分配主设备号 */4 t, Y9 {" x8 S$ x; p( `- @
        major = register_chrdev(0, "fifth_drv", &fifth_drv_fops);3 }: W+ C7 v) c1 o; b3 e
6 m7 T, s7 n4 Z8 t' w" l
        /* 创建fifthdrv类 */& y8 i. U+ W- `
        fifthdrv_class = class_create(THIS_MODULE, "fifthdrv");8 l5 S  ^6 Q8 D+ u$ a6 x; T

. B. ^4 i7 U. m  F) a4 F        /* 在fifthdrv类下创建buttons设备,供应用程序打开设备*/! ~7 E! E) |! M0 q' s  @
        fifthdrv_device = device_create(fifthdrv_class, NULL, MKDEV(major, 0), NULL, "buttons");/ B5 G" u/ C: Z# e6 Z* F" }2 |

/ D0 Q. y: [$ n# s        return 0;3 Q, k4 ?  L! ?8 e$ |# k, n# R
}
! H1 M8 g  w  ^) P/ ^: n* W# E2 V( H2 S+ q4 z1 w. R' U
/* 驱动出口函数 */
# R+ `+ K9 L: A# c2 kstatic void fifth_drv_exit(void)
% v6 w8 |" S8 m: t$ l" f% [; [; @9 }& Q{
- X$ X0 ^: W( k9 s8 M  w7 f3 g, h        unregister_chrdev(major, "fifth_drv");7 s' k" y  B5 q1 ?2 `$ {
        device_unregister(fifthdrv_device);  //卸载类下的设备
$ j; z: d) G8 U* Y: p7 D        class_destroy(fifthdrv_class);                //卸载类  ~- Q- D  b" ?; P- ^' x  ?* Y
}
7 r+ a0 J' K  P/ f
- p* A+ f: M" \- r# a$ Fmodule_init(fifth_drv_init);  //用于修饰入口函数
' V- l$ X3 E' u2 smodule_exit(fifth_drv_exit);  //用于修饰出口函数       
# O; R$ u3 v; q6 i1 ]5 l
/ |7 s" l% H/ B1 X9 `3 xMODULE_AUTHOR("LWJ");( D. g7 @% D) G5 a) e6 G
MODULE_DESCRIPTION("Just for Demon");0 m! ]4 E; u& J; s
MODULE_LICENSE("GPL");  //遵循GPL协议6 Y1 X, N: k1 i* V

& f, N7 \* C. c. U应用测试程序源码:3 v) q3 _& Z% y- P5 Q8 B
' t, B' p, I1 w+ o
#include <stdio.h>
/ s! |. E2 c6 r* A! |! k#include <sys/types.h>
! I+ X' z- }# L( x0 J% J, d- F- k#include <sys/stat.h>5 H/ u8 u9 w8 z6 x3 U3 c
#include <fcntl.h>& d% U: f0 o& A* ]+ N. ]
#include <unistd.h>        //sleep
- V5 h- E, S' k" a7 s#include <poll.h>
( U$ W5 C# _) l4 Q#include <signal.h>
- R) E  m6 d4 p# f0 ~#include <fcntl.h>% O( @% e5 @+ u0 |9 P% l1 L
: `4 q) Y. g: L  X  w7 |
int fd;! |; B& V, g- n0 x2 \
7 i$ I! u. ?' y) J: e0 B
void mysignal_fun(int signum)
2 _# |  U( W- }: h3 ^! F/ Q$ P{
- g" m# @5 Z7 w        unsigned char key_val;
! I$ x) Q. A& ^# n3 e& d        read(fd,&key_val,1);
, y  q) W1 R7 D; L* Y% ?        printf("key_val = 0x%x\n",key_val);
  {, Q" b: |; O* q2 ?}
+ G8 a6 J. T/ Q# |
* N; C. @0 |. g) R6 d4 Z
  c, ^% g# J  U: t0 _/* fifth_test/ T0 |) i, y. q5 ?9 M( y5 y$ F9 B# G# A
*/   W& X7 y. ^6 L0 x
int main(int argc ,char *argv[])
8 J/ }7 O6 R) w' y2 L8 Z7 x{
; ?( c3 s  u* r! E2 s9 j  A        int flag;0 d4 Q' Q4 V6 o9 V# b
        signal(SIGIO,mysignal_fun);
" A* q5 D( G8 |! s. {" c# z
" `( a' T) p) w& Q        fd = open("/dev/buttons",O_RDWR);
  G4 Y6 e7 d/ Y+ n! r) k8 J5 U, E        if (fd < 0)1 [; g) u% ~; v
        {: D9 X) y3 m  H
                printf("open error\n");
2 V' Z6 o6 X+ S4 a/ v        }% @  C; o- E+ u0 p0 Z7 \

2 |1 _9 u5 u& V$ F+ r        /* F_SETOWN:  Set the process ID* ?9 j5 K0 j& n% |
         *  告诉内核,发给谁. B$ c0 y& G  N& U6 z' x2 w  d
         */  v; x" U  y& D4 H, Q1 D! w
        fcntl(fd, F_SETOWN, getpid());
/ h2 ]8 A' I! K4 v4 J: u
0 t) f" O8 M5 ~2 I4 L! ?2 X        /*  F_GETFL :Read the file status flags
0 H+ C* U2 m+ \0 W         *  读出当前文件的状态' T  c. C' A7 U( Q/ j6 l: c9 x
         */
5 G. ]$ U& K, o- B# [8 w* h        flag = fcntl(fd,F_GETFL);
; b2 p0 j' T- f1 a% K
' ~/ `# W$ L! I3 X        /* F_SETFL: Set the file status flags to the value specified by arg
3 g) D7 t) @0 x- V         * int fcntl(int fd, int cmd, long arg);' X+ Z6 n8 M. T) @& I* a( E8 u  X
         * 修改当前文件的状态,添加异步通知功能: J2 i8 ^3 o, o3 L) x
         */% R5 z+ I% C5 K$ g, u2 s
        fcntl(fd,F_SETFL,flag | FASYNC);
* A. S- V7 c' y4 B       
9 p9 l5 ^! L" D! N$ K3 k/ f0 d3 {        while(1)7 c7 H/ m7 `' W9 A: M, ~' L. o
        {
8 M3 o# Q, g0 \* U5 u  w& R                /* 为了测试,主函数里,什么也不做 */
5 @) Y# @: _3 M& ]; e; e- I; W                sleep(1000);! f; L, x9 W/ q: N$ p$ D( \) N3 R
        }
/ ?) O, g. y& Y% e* U8 ^9 o" [8 L& h        return 0;
7 S+ X; R$ ^$ F. R) H}. i9 h% S. G5 x; R
& S  {1 r# j. o9 A3 F
测试步骤:
6 O* S6 i4 z7 Y9 S' f% f* z  p( t$ I
[WJ2440]# ls
" H: O4 P: Z2 y, |0 T. vQt             fifth_drv.ko   lib            sddisk         udisk
) ^% q# U6 c6 u7 u/ z. W. {TQLedtest      fifth_test     linuxrc        second_drv.ko  usr
- i9 q3 P1 p+ h) k3 r$ bapp_test       first_drv.ko   mnt            second_test    var
' K, p8 m, O4 a) c3 l/ O; Fbin            first_test     opt            sys            web
* c; @1 v1 v/ z' [" f( }; rdev            fourth_drv.ko  proc           third_drv.ko5 A2 M. K) a! q0 I1 i: E0 U* v% e
driver_test    fourth_test    root           third_test: t, V+ r' @5 ]% \
etc            home           sbin           tmp. Q  G5 m0 @" G, T: F- I  M5 L
[WJ2440]# insmod fifth_drv.ko / V" s! U$ y' |3 t* [
[WJ2440]# lsmod9 g1 q, Z; Y- u6 `8 ~
fifth_drv 3360 0 - Live 0xbf0060007 J/ p% x/ Q. w* J) w! z% k
[WJ2440]# ls /dev/buttons -l6 `, P( W% \$ o; ?% M& U; C; ?
crw-rw----    1 root     root      252,   0 Jan  2 04:27 /dev/buttons9 V, c6 F5 |8 s" k$ \
[WJ2440]# ./fifth_test . @4 |( ?  B1 H/ r, q8 V2 v& R* S- q
key_val = 0x16 G/ o2 T5 d  V  w+ M% v. x
key_val = 0x81
. ]( ]7 f9 }, k. p' _: H+ M7 ~* akey_val = 0x4
- w6 ^7 U1 I# a2 m- Mkey_val = 0x84
5 N- Q  R9 K! ]9 O9 |* z0 b2 k& k: Rkey_val = 0x2
& h7 k) ?: F$ hkey_val = 0x82
  C' P- R8 i2 Z; lkey_val = 0x3
4 ]' ^: P8 @8 nkey_val = 0x830 ^1 j9 f+ E9 V* f2 x
key_val = 0x4
* ^* V7 z. g6 m# Wkey_val = 0x84! [* p! k7 K) Z! l
key_val = 0x84
/ c6 B2 T; m7 w+ C( G. O3 ?
1 m5 W: P6 b2 E9 Z由测试可知,当无按键按下时,应用测试程序一直在sleep,当有按键按下时,signal会被调用,最终会调用mysignal_fun,在此函数里read(fd,&key_val,1);会去读出按键值,这样一来,应用程序就相当于不用主动去读数据了,每当驱动里有数据时,就会告诉应用程序有数据了,你该去读数据了,此时read函数才会被调用。
3 S4 _( y- R* ]  B- f* M
. U7 h% U3 O( a+ X/ ^* W
# Y/ o7 b# u# P3 j/ ]2 b这里最后总结一下老师的笔记:* i7 i9 k3 F- v" s" l$ W2 r

# B; u6 ~& s6 z! f为了使设备支持异步通知机制,驱动程序中涉及以下3项工作:
1 Z) h: v- u. D0 w$ u+ A1. 支持F_SETOWN命令,能在这个控制命令处理中设置filp->f_owner为对应进程ID。
* ~; A: t( f3 ~# f, A1 a   不过此项工作已由内核完成,设备驱动无须处理。
9 P! |" u" x# d& c9 k2. 支持F_SETFL命令的处理,每当FASYNC标志改变时,驱动程序中的fasync()函数将得以执行。2 ]/ L# D# v' W4 w: F
   驱动中应该实现fasync()函数。7 Y, e3 R( T0 A5 Z
3. 在设备资源可获得时,调用kill_fasync()函数激发相应的信号. x# Y. E- ]+ d# {3 b6 Q
2 Z7 j* n% n8 P) Q
应用程序:$ @  K6 q4 ]7 ?0 O4 O, Z
fcntl(fd, F_SETOWN, getpid());  // 告诉内核,发给谁. l+ t2 U* v- L1 A, s

  n7 G( R. T- o! N: s$ e" Y6 oOflags = fcntl(fd, F_GETFL);   
" N' E+ c! v/ v& o3 w: ifcntl(fd, F_SETFL, Oflags | FASYNC);  // 改变fasync标记,最终会调用到驱动的faync > fasync_helper:初始化/释放fasync_struct
& u% `  D$ g2 S9 _) A( ]+ M7 |
6 Q- N6 M2 R0 t# m% k6 k3 c  m" B$ R- [% }

) F, u5 s! [+ L6 }

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-11-25 22:41 , Processed in 0.171875 second(s), 23 queries , Gzip On.

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

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

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