• 驱动基石之异步通知


    异步通知的流程

    在这里插入图片描述
    重点从②开始:
    ② APP 给 SIGIO 这个信号注册信号处理函数 func,以后 APP 收到 SIGIO
    信号时,这个函数会被自动调用;
    ③ 把 APP 的 PID(进程 ID)告诉驱动程序,这个调用不涉及驱动程序,在内
    核的文件系统层次记录 PID;
    ④ 读取驱动程序文件 Flag;
    ⑤ 设置 Flag 里面的 FASYNC 位为 1:当 FASYNC 位发生变化时,会导致驱
    动程序的 fasync 被调用;
    ⑥⑦ 调 用 faync_helper , 它 会 根 据 FAYSNC 的 值 决 定 是 否 设 置
    button_async->fa_file=驱动文件 filp:
    驱动文件 filp 结构体里面含有之前设置的 PID。
    ⑧ APP 可以做其他事;
    ⑨⑩ 按下按键,发生中断,驱动程序的中断服务程序被调用,里面调用
    kill_fasync 发信号;
    ⑪⑫⑬ APP 收到信号后,它的信号处理函数被自动调用,可以在里面调用
    read 函数读取按键。

    上述是韦东山老师的笔记,大概简描下流程就是:
    APP程序(进程)给要接受的信号注册一个信号处理函数,APP程序也要将自己的进程号告诉驱动程序,通过设置FASYNC 位来使启动程序的fasync 函数被调用。fasync 函数里调用fasync_helper 函数来设置指针 button_fasync(自己定义的struct fasync_struct类型的指针),fasync_helper 函数的简要 作用:

    在这里插入图片描述
    **注意:**一定要设置FASYNC 位有效(想当于异步通知的开关)。
    然后在按键中断处理函数里调用kill_fasync 函数去发送信号。app程序正在运行,如果有按键按下则按键中断处理函数会发送信号给app,然后app跳转信号处理函数执行。

    代码

    驱动程序代码

    #include 
    #include 
    
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    struct gpio_key{
    	int gpio;
    	struct gpio_desc *gpiod;
    	int flag;
    	int irq;
    } ;
    
    static struct gpio_key *gpio_keys_100ask;
    
    /* 主设备号                                                                 */
    static int major = 0;
    static struct class *gpio_key_class;
    
    /* 环形缓冲区 */
    #define BUF_LEN 128
    static int g_keys[BUF_LEN];
    static int r, w;
    
    struct fasync_struct *button_fasync;
    
    #define NEXT_POS(x) ((x+1) % BUF_LEN)
    
    static int is_key_buf_empty(void)
    {
    	return (r == w);
    }
    
    static int is_key_buf_full(void)
    {
    	return (r == NEXT_POS(w));
    }
    
    static void put_key(int key)
    {
    	if (!is_key_buf_full())
    	{
    		g_keys[w] = key;
    		w = NEXT_POS(w);
    	}
    }
    
    static int get_key(void)
    {
    	int key = 0;
    	if (!is_key_buf_empty())
    	{
    		key = g_keys[r];
    		r = NEXT_POS(r);
    	}
    	return key;
    }
    
    
    static DECLARE_WAIT_QUEUE_HEAD(gpio_key_wait);
    
    /* 实现对应的open/read/write等函数,填入file_operations结构体                   */
    static ssize_t gpio_key_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
    {
    	//printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    	int err;
    	int key;
    	
    	wait_event_interruptible(gpio_key_wait, !is_key_buf_empty());
    	key = get_key();
    	err = copy_to_user(buf, &key, 4);
    	
    	return 4;
    }
    
    static unsigned int gpio_key_drv_poll(struct file *fp, poll_table * wait)
    {
    	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    	poll_wait(fp, &gpio_key_wait, wait);
    	return is_key_buf_empty() ? 0 : POLLIN | POLLRDNORM;
    }
    
    static int gpio_key_drv_fasync(int fd, struct file *file, int on)
    {
    	if (fasync_helper(fd, file, on, &button_fasync) >= 0)
    		return 0;
    	else
    		return -EIO;
    }
    
    
    /* 定义自己的file_operations结构体                                              */
    static struct file_operations gpio_key_drv = {
    	.owner	 = THIS_MODULE,
    	.read    = gpio_key_drv_read,
    	.poll    = gpio_key_drv_poll,
    	.fasync  = gpio_key_drv_fasync,
    };
    
    
    static irqreturn_t gpio_key_isr(int irq, void *dev_id)
    {
    	struct gpio_key *gpio_key = dev_id;
    	int val;
    	int key;
    	
    	val = gpiod_get_value(gpio_key->gpiod);
    	
    
    	printk("key %d %d\n", gpio_key->gpio, val);
    	key = (gpio_key->gpio << 8) | val;
    	put_key(key);
    	wake_up_interruptible(&gpio_key_wait);
    	kill_fasync(&button_fasync, SIGIO, POLL_IN);
    	
    	return IRQ_HANDLED;
    }
    
    /* 1. 从platform_device获得GPIO
     * 2. gpio=>irq
     * 3. request_irq
     */
    static int gpio_key_probe(struct platform_device *pdev)
    {
    	int err;
    	struct device_node *node = pdev->dev.of_node;
    	int count;
    	int i;
    	enum of_gpio_flags flag;
    		
    	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    
    	count = of_gpio_count(node);
    	if (!count)
    	{
    		printk("%s %s line %d, there isn't any gpio available\n", __FILE__, __FUNCTION__, __LINE__);
    		return -1;
    	}
    
    	gpio_keys_100ask = kzalloc(sizeof(struct gpio_key) * count, GFP_KERNEL);
    	for (i = 0; i < count; i++)
    	{
    		gpio_keys_100ask[i].gpio = of_get_gpio_flags(node, i, &flag);
    		if (gpio_keys_100ask[i].gpio < 0)
    		{
    			printk("%s %s line %d, of_get_gpio_flags fail\n", __FILE__, __FUNCTION__, __LINE__);
    			return -1;
    		}
    		gpio_keys_100ask[i].gpiod = gpio_to_desc(gpio_keys_100ask[i].gpio);
    		gpio_keys_100ask[i].flag = flag & OF_GPIO_ACTIVE_LOW;
    		gpio_keys_100ask[i].irq  = gpio_to_irq(gpio_keys_100ask[i].gpio);
    	}
    
    	for (i = 0; i < count; i++)
    	{
    		err = request_irq(gpio_keys_100ask[i].irq, gpio_key_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "100ask_gpio_key", &gpio_keys_100ask[i]);
    	}
    
    	/* 注册file_operations 	*/
    	major = register_chrdev(0, "100ask_gpio_key", &gpio_key_drv);  /* /dev/gpio_key */
    
    	gpio_key_class = class_create(THIS_MODULE, "100ask_gpio_key_class");
    	if (IS_ERR(gpio_key_class)) {
    		printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    		unregister_chrdev(major, "100ask_gpio_key");
    		return PTR_ERR(gpio_key_class);
    	}
    
    	device_create(gpio_key_class, NULL, MKDEV(major, 0), NULL, "100ask_gpio_key"); /* /dev/100ask_gpio_key */
            
        return 0;
        
    }
    
    static int gpio_key_remove(struct platform_device *pdev)
    {
    	//int err;
    	struct device_node *node = pdev->dev.of_node;
    	int count;
    	int i;
    
    	device_destroy(gpio_key_class, MKDEV(major, 0));
    	class_destroy(gpio_key_class);
    	unregister_chrdev(major, "100ask_gpio_key");
    
    	count = of_gpio_count(node);
    	for (i = 0; i < count; i++)
    	{
    		free_irq(gpio_keys_100ask[i].irq, &gpio_keys_100ask[i]);
    	}
    	kfree(gpio_keys_100ask);
        return 0;
    }
    
    
    static const struct of_device_id ask100_keys[] = {
        { .compatible = "100ask,gpio_key" },
        { },
    };
    
    /* 1. 定义platform_driver */
    static struct platform_driver gpio_keys_driver = {
        .probe      = gpio_key_probe,
        .remove     = gpio_key_remove,
        .driver     = {
            .name   = "100ask_gpio_key",
            .of_match_table = ask100_keys,
        },
    };
    
    /* 2. 在入口函数注册platform_driver */
    static int __init gpio_key_init(void)
    {
        int err;
        
    	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    	
        err = platform_driver_register(&gpio_keys_driver); 
    	
    	return err;
    }
    
    /* 3. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数
     *     卸载platform_driver
     */
    static void __exit gpio_key_exit(void)
    {
    	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    
        platform_driver_unregister(&gpio_keys_driver);
    }
    
    
    /* 7. 其他完善:提供设备信息,自动创建设备节点                                     */
    
    module_init(gpio_key_init);`在这里插入代码片`
    module_exit(gpio_key_exit);
    
    MODULE_LICENSE("GPL");
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262

    应用程序代码

    
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    static int fd;
    static void sig_func(int sig)
    {
    	int val;
    	read(fd, &val, 4);
    	printf("get button : 0x%x\n", val);
    }
    
    /*
     * ./button_test /dev/100ask_button0
     *
     */
    int main(int argc, char **argv)
    {
    	int val;
    	struct pollfd fds[1];
    	int timeout_ms = 5000;
    	int ret;
    	int	flags;
    	
    	/* 1. 判断参数 */
    	if (argc != 2) 
    	{
    		printf("Usage: %s \n", argv[0]);
    		return -1;
    	}
    
    	signal(SIGIO, sig_func);
    
    	/* 2. 打开文件 */
    	fd = open(argv[1], O_RDWR);
    	if (fd == -1)
    	{
    		printf("can not open file %s\n", argv[1]);
    		return -1;
    	}
    
    	fcntl(fd, F_SETOWN, getpid());
    	flags = fcntl(fd, F_GETFL);
    	fcntl(fd, F_SETFL, flags | FASYNC);
    
    	while (1)
    	{
    		printf("www.100ask.net \n");
    		sleep(2);
    	}
    	
    	close(fd);
    	
    	return 0;
    }
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
  • 相关阅读:
    learnOpenGl
    JAVA ----- Map 集合
    Vue2.0 —— Vue.nextTick(this.$nextTick)源码探秘
    PMP模拟题 | 每日一练,快速提分
    My Seventy-first Page - 目标和 - By Nicolas
    高效处理海量慢SQL日志文件:Java与JSQLParser去重方案详解
    小红书账号怎么做起来的呢?干货!快收藏起来!
    【Sql】MVCC有关问题,以及锁,日志和主从复制原理
    申请宣告专利权无效的主体有哪些 ?
    LeetCode刷题2:链表篇
  • 原文地址:https://blog.csdn.net/m0_57678852/article/details/134290584