六、异步通知

 

在此之前的代码,我们都是应用程序主动去read()按键值

这章所要涉及的异步通知是一旦设备就绪,则驱动主动通知应用程序,这样应用程序不需要查询设备状态。这一点类似于“中断”

 

 

一、应用程序异步通知signal()

这章的异步通知使用的是UNIX环境高级编程第十章信号。由于是异步通知,因此我们还需要使用fcntl(fd, F_SETFL, oflag | FASYNC)将应用程序的文件描述符设置为异步模式

 

fcntl()函数最终会调用驱动程序中的fasync() -> fasync_helper(),因此在驱动程序中我们只需要调用fasync_helper()函数即可

fasync_helper()函数的作用就是初始化fasync_struct,包括分配内存和设置属性,最后需要在驱动的release()函数里把fasync_helper()初始化的东西free掉

 

应用程序的示例代码如下:

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <sys/types.h>
 4 #include <sys/stat.h>
 5 #include <fcntl.h>
 6 #include <string.h>
 7 #include <signal.h>
 8 
 9 int fd;
10 
11 static void sig_handler(int signo)
12 {
13     unsigned char key_val;
14     read(fd, &key_val, 1);
15     printf("key_val = 0x%x\n", key_val);
16 }
17 
18 int main(int argc, char** argv)
19 {
20     int oflags = 0;
21     
22     signal(SIGIO, sig_handler);
23     
24     fd = open("/dev/key", O_RDWR);
25     if (fd < 0) {
26         printf("can't open /dev/key\n");
27         return -1;
28     }
29     
30     fcntl(fd, F_SETOWN, getpid());
31     oflags = fcntl(fd, F_GETFL);
32     fcntl(fd, F_SETFL, oflags | FASYNC);
33 
34     while (1) {
35         sleep(1000);
36     }
37     
38     close(fd);
39 
40     return 0;
41 }

 

应用程序完成的有以下几个任务:

1. fcntl(fd, F_SETOWN, getpid())设置文件拥有者为本进程,这样驱动程序发出的信号才能被本进程接到

2. fcntl(fd, F_SETFL, oflags | FASYNC)设置应用程序支持异步通知

3. 通过signal()连接信号和信号处理函数

 

 

二、驱动程序异步通知fasync()

在分析完应用程序之后,我们需要确定驱动程序需要做什么,如下图:

由图,可得出驱动需要做的有以下几点:

1. 设置file->f_owner,这个已经由内核帮我们完成了

2. 编写fasync()函数,里面调用fasync_helper()函数

3. 在资源可获得时,调用kill_fasync()函数释放信号

 

我们现在来看一下fasync()系统调用过程:

SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)
  -> do_fcntl(fd, cmd, arg, f.file);
    -> case F_SETFL:
      -> setfl(fd, filp, arg);
        -> filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0);    /* 驱动程序的fasync() */
    -> case F_SETOWN:
      -> f_setown(filp, arg, 1);

 

异步通知所使用保存属性的结构体是fasync_struct

fasync()、fasync_helper()和kill_fasync()函数声明如下:

int (*fasync) (int fd, struct file *filp, int mode);

int fasync_helper(int fd, struct file * filp, int mode, struct fasync_struct **fapp)

void kill_fasync(struct fasync_struct **fp, int sig, int band)

 

驱动程序模版如下:

struct key_device {
    ...
    struct fasync_struct *fasync;
};

static int key_fasync(int fd, struct file *filp, int mode)
{
    struct key_device *dev = filp->private_data;

    // 初始化fasync
    return fasync_helper(fd, filp, mode, &dev->fasync);
}

static struct file_operations key_fops = {
    ...
    .fasync        = key_fasync,
};

static ssize_t key_read(struct file *filp, char __user *buf, size_t len, loff_t * loff)
{
    ...
    schedule();        // 休眠

    // 有数据,释放信号
    kill_fasync(&dev->fasync, SIGIO, POLL_IN);

    mutex_lock(&dev->lock);
    copy_to_user(buf, &key_val, 1);
    mutex_unlock(&dev->lock);
    ...
}

static int key_release(struct inode *nodep, struct file *filp)
{
    key_fasync(-1, filp, 0);    // 将文件从异步通知列表中删除
    ...
}

 

若需要完整驱动程序代码,可查看:

key源代码:

  1 #include <linux/module.h>
  2 #include <linux/fs.h>
  3 #include <linux/init.h>
  4 #include <linux/cdev.h>
  5 #include <linux/slab.h>
  6 #include <linux/device.h>
  7 #include <linux/irq.h>
  8 #include <linux/interrupt.h>
  9 #include <linux/wait.h>
 10 #include <linux/timer.h>
 11 #include <linux/gpio.h>
 12 #include <linux/sched.h>
 13 #include <linux/mutex.h>
 14 
 15 #include <asm/uaccess.h>
 16 #include <asm/irq.h>
 17 #include <asm/io.h>
 18 
 19 #include <mach/gpio.h>
 20 
 21 #define KEY_MAJOR        255
 22 
 23 struct pin_desc {
 24     int gpio;
 25     int val;
 26     char *name;
 27 };
 28 
 29 struct key_device {
 30     struct cdev cdev;
 31     wait_queue_head_t r_head;
 32     wait_queue_head_t w_head;
 33     struct mutex lock;
 34     struct fasync_struct *fasync;
 35 };
 36 
 37 static struct pin_desc desc[4] = {
 38     { EXYNOS4_GPX3(2), 0x01, "KEY0" },
 39     { EXYNOS4_GPX3(3), 0x02, "KEY1" },
 40     { EXYNOS4_GPX3(4), 0x03, "KEY2" },
 41     { EXYNOS4_GPX3(5), 0x04, "KEY3" },
 42 };
 43 
 44 static int g_major = KEY_MAJOR;
 45 module_param(g_major, int, S_IRUGO);
 46 
 47 static struct key_device*    dev;
 48 static struct class*        scls;
 49 static struct device*        sdev;
 50 static unsigned char        key_val;
 51 
 52 static irqreturn_t key_interrupt(int irq, void *dev_id)
 53 {
 54     struct pin_desc *pindesc = (struct pin_desc *)dev_id;
 55     unsigned int tmp;
 56 
 57     tmp = gpio_get_value(pindesc->gpio);
 58 
 59     /* active low */
 60     printk(KERN_DEBUG "KEY %d: %08x\n", pindesc->val, tmp);
 61 
 62     if (tmp)
 63         key_val = pindesc->val;
 64     else
 65         key_val = pindesc->val | 0x80;
 66 
 67     set_current_state(TASK_RUNNING);
 68 
 69     return IRQ_HANDLED;
 70 }
 71 
 72 static ssize_t key_read(struct file *filp, char __user *buf, size_t len, loff_t * loff)
 73 {
 74     struct key_device *dev = filp->private_data;
 75 
 76     // 声明等待队列
 77     DECLARE_WAITQUEUE(rwait, current);    
 78     mutex_lock(&dev->lock);        // 上锁
 79     add_wait_queue(&dev->r_head, &rwait);
 80 
 81     // 休眠
 82     __set_current_state(TASK_INTERRUPTIBLE);
 83     mutex_unlock(&dev->lock);    // 解锁
 84     schedule();
 85 
 86     // 有数据
 87     kill_fasync(&dev->fasync, SIGIO, POLL_IN);
 88 
 89     mutex_lock(&dev->lock);        // 上锁
 90     copy_to_user(buf, &key_val, 1);
 91     mutex_unlock(&dev->lock);    // 解锁
 92 
 93     remove_wait_queue(&dev->r_head, &rwait);
 94     set_current_state(TASK_RUNNING);
 95 
 96     return 1;
 97 }
 98 
 99 static int key_open(struct inode *nodep, struct file *filp)
100 {
101     struct key_device *dev = container_of(nodep->i_cdev, struct key_device, cdev);
102     // 放入私有数据中
103     filp->private_data = dev;
104 
105     int irq;
106     int i, err = 0;
107 
108     for (i = 0; i < ARRAY_SIZE(desc); i++) {
109         if (!desc[i].gpio)
110             continue;
111 
112         irq = gpio_to_irq(desc[i].gpio);
113         err = request_irq(irq, key_interrupt, IRQ_TYPE_EDGE_BOTH, 
114                 desc[i].name, (void *)&desc[i]);
115         if (err)
116             break;
117     }
118     
119     if (err) {
120         i--;
121         for (; i >= 0; i--) {
122             if (!desc[i].gpio)
123                 continue;
124 
125             irq = gpio_to_irq(desc[i].gpio);
126             free_irq(irq, (void *)&desc[i]);
127         }
128         return -EBUSY;
129     }
130     
131     init_waitqueue_head(&dev->r_head);
132     mutex_init(&dev->lock);        // 初始化
133 
134     return 0;
135 }
136 
137 static int key_fasync(int fd, struct file *filp, int mode)
138 {
139     struct key_device *dev = filp->private_data;
140 
141     return fasync_helper(fd, filp, mode, &dev->fasync);
142 }
143 
144 static int key_release(struct inode *nodep, struct file *filp)
145 {
146     key_fasync(-1, filp, 0);
147     
148     // 释放中断
149     int irq, i;
150 
151     for (i = 0; i < ARRAY_SIZE(desc); i++) {
152         if (!desc[i].gpio)
153             continue;
154 
155         irq = gpio_to_irq(desc[i].gpio);
156         free_irq(irq, (void *)&desc[i]);
157     }
158 
159     return 0;
160 }
161 
162 static struct file_operations key_fops = {
163     .owner    = THIS_MODULE,
164     .read    = key_read,
165     .open        = key_open,
166     .fasync        = key_fasync,
167     .release    = key_release,
168 };
169 
170 static int keys_init(void)
171 {
172     int ret;
173     int devt;
174     if (g_major) {
175         devt = MKDEV(g_major, 0);
176         ret = register_chrdev_region(devt, 1, "key");
177     }
178     else {
179         ret = alloc_chrdev_region(&devt, 0, 1, "key");
180         g_major = MAJOR(devt);
181     }
182 
183     if (ret)
184         return ret;
185 
186     dev = kzalloc(sizeof(struct key_device), GFP_KERNEL);
187     if (!dev) {
188         ret = -ENOMEM;
189         goto fail_alloc;
190     }
191 
192     cdev_init(&dev->cdev, &key_fops);
193     ret = cdev_add(&dev->cdev, devt, 1);
194     if (ret)
195         return ret;
196 
197     scls = class_create(THIS_MODULE, "key");
198     sdev = device_create(scls, NULL, devt, NULL, "key");
199 
200     return 0;
201 
202 fail_alloc:
203     unregister_chrdev_region(devt, 1);
204 
205     return ret;
206 }
207 
208 static void keys_exit(void)
209 {
210     dev_t devt = MKDEV(g_major, 0);
211 
212     device_destroy(scls, devt);
213     class_destroy(scls);
214 
215     cdev_del(&(dev->cdev));
216     kfree(dev);
217 
218     unregister_chrdev_region(devt, 1);
219 }
220 
221 module_init(keys_init);
222 module_exit(keys_exit);
223 
224 MODULE_LICENSE("GPL");
View Code

Makefile:

 1 KERN_DIR = /work/tiny4412/tools/linux-3.5
 2 
 3 all:
 4     make -C $(KERN_DIR) M=`pwd` modules 
 5 
 6 clean:
 7     make -C $(KERN_DIR) M=`pwd` modules clean
 8     rm -rf modules.order
 9 
10 obj-m    += key.o
View Code

测试文件:

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <sys/types.h>
 4 #include <sys/stat.h>
 5 #include <fcntl.h>
 6 #include <string.h>
 7 #include <signal.h>
 8 
 9 int fd;
10 
11 static void sig_handler(int signo)
12 {
13     unsigned char key_val;
14     read(fd, &key_val, 1);
15     printf("key_val = 0x%x\n", key_val);
16 }
17 
18 int main(int argc, char** argv)
19 {
20     int oflags = 0;
21     
22     signal(SIGIO, sig_handler);
23     
24     fd = open("/dev/key", O_RDWR);
25     if (fd < 0) {
26         printf("can't open /dev/key\n");
27         return -1;
28     }
29     
30     fcntl(fd, F_SETOWN, getpid());
31     oflags = fcntl(fd, F_GETFL);
32     fcntl(fd, F_SETFL, oflags | FASYNC);
33 
34     while (1) {
35         sleep(1000);
36     }
37     
38     close(fd);
39 
40     return 0;
41 }
View Code

 

 

下一章  七、内核定时器

 

转载于:https://www.cnblogs.com/Lioker/p/10856478.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值