千家信息网

linux驱动poll机制简要介绍是什么

发表于:2024-11-20 作者:千家信息网编辑
千家信息网最后更新 2024年11月20日,本篇文章给大家分享的是有关linux驱动poll机制简要介绍是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。#include #in
千家信息网最后更新 2024年11月20日linux驱动poll机制简要介绍是什么

本篇文章给大家分享的是有关linux驱动poll机制简要介绍是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。

#include #include #include #include #include #include #include #include #include #include #include #include static struct class *forthdrv_class;static struct class_device    *forthdrv_class_dev;volatile unsigned long *gpfcon;volatile unsigned long *gpfdat;volatile unsigned long *gpgcon;volatile unsigned long *gpgdat;static DECLARE_WAIT_QUEUE_HEAD(button_waitq);/* 中断事件标志, 中断服务程序将它置1,forth_drv_read将它清0 */static volatile int ev_press = 0;struct pin_desc{        unsigned int pin;        unsigned int key_val;};/* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 *//* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */static unsigned char key_val;struct pin_desc pins_desc[4] = {        {S3C2410_GPF0, 0x01},        {S3C2410_GPF2, 0x02},        {S3C2410_GPG3, 0x03},        {S3C2410_GPG11, 0x04},};/*  * 确定按键值  */static irqreturn_t buttons_irq(int irq, void *dev_id){        struct pin_desc * pindesc = (struct pin_desc *)dev_id;        unsigned int pinval;        //这里怎么知道是哪个引脚触发的中断? 这里并不判断是哪个按键产生的中断, 如果要获取当前的中断号可以打印 irq 参数来查看        pinval = s3c2410_gpio_getpin(pindesc->pin);//该函数返回GPxDAT的值, 如GPF9则返回 0X100(剩余位被mask), 而不是 1        if (pinval)        {                /* 松开 */                key_val = 0x80 | pindesc->key_val;        }        else        {                /* 按下 */                key_val = pindesc->key_val;        }    ev_press = 1;                                       /* 表示中断发生了 */    wake_up_interruptible(&button_waitq);   /* 唤醒休眠的进程 */                return IRQ_RETVAL(IRQ_HANDLED);}static int forth_drv_open(struct inode *inode, struct file *file){        /* 配置GPF0,2为输入引脚 */        /* 配置GPG3,11为输入引脚 */        request_irq(IRQ_EINT0,  buttons_irq, IRQT_BOTHEDGE, "S2", &pins_desc[0]);        request_irq(IRQ_EINT2,  buttons_irq, IRQT_BOTHEDGE, "S3", &pins_desc[1]);        request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", &pins_desc[2]);        request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", &pins_desc[3]);             return 0;}ssize_t forth_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos){        if (size != 1)                return -EINVAL;        /* 如果没有按键动作, 休眠 */        wait_event_interruptible(button_waitq, ev_press);        /* 如果有按键动作, 返回键值 */        copy_to_user(buf, &key_val, 1);        ev_press = 0;                return 1;}int forth_drv_close(struct inode *inode, struct file *file){        free_irq(IRQ_EINT0, &pins_desc[0]);        free_irq(IRQ_EINT2, &pins_desc[1]);        free_irq(IRQ_EINT11, &pins_desc[2]);        free_irq(IRQ_EINT19, &pins_desc[3]);        return 0;}static unsigned forth_drv_poll(struct file *file, poll_table *wait){        unsigned int mask = 0;        poll_wait(file, &button_waitq, wait); // 不会立即休眠        if (ev_press)                mask |= POLLIN | POLLRDNORM;        return mask;}static struct file_operations sencod_drv_fops = {    .owner   =  THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */    .open    =  forth_drv_open,             .read    = forth_drv_read,            .release =  forth_drv_close,        .poll    =  forth_drv_poll,};int major;static int forth_drv_init(void){        major = register_chrdev(0, "forth_drv", &sencod_drv_fops);        forthdrv_class = class_create(THIS_MODULE, "forth_drv");        forthdrv_class_dev = class_device_create(forthdrv_class, NULL, MKDEV(major, 0), NULL, "buttons"); /* /dev/buttons */        gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);        gpfdat = gpfcon + 1;        gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);        gpgdat = gpgcon + 1;        return 0;}static void forth_drv_exit(void){        unregister_chrdev(major, "forth_drv");        class_device_unregister(forthdrv_class_dev);        class_destroy(forthdrv_class);        iounmap(gpfcon);        iounmap(gpgcon);        return 0;}module_init(forth_drv_init);module_exit(forth_drv_exit);MODULE_LICENSE("GPL");/*poll 执行的步骤 : poll 分析:应用程序:poll         sys_poll                do_sys_poll                        poll_initwait(&table)                                init_poll_funcptr(&pwq->pt, __pollwait) >> table->pt->qproc = __pollwait;                                    据说 xxx_fops->xxx_drv_poll 调中的 poll_wait 最后调用的就是 __pollwait 函数, 怎么看出来的?                        do_poll(nfds, head, &table, timeout)                                //遍历传入的所有描述符                                for (;;)                                {                                        //mask = file->f_op->poll(file, pwait);  这里的poll就是驱动里的 xxx_drv_poll(struct file *file, poll_table *wait), mask就是驱动中的返回值                                        if (do_pollfd(pfd, pt)) {                                                count++;                                                pt = NULL;                                        }                                        //如果驱动就绪返回非0值, 则跳出循环                                        if (count || !*timeout || signal_pending(current))                                break;                           //如果未就绪或者且时间未到则休眠                                        schedule_timeout(__timeout);                                }例程执行过程:调用poll 1. 先注册 __pollwait 就是xxx_drv_poll 中 poll_wait 函数最终调用的内容 2. 然后调用  do_poll, 遍历传入的描述符, do_pollfd就是调用xxx_drv_poll, 它将本进程添加到驱动设置的等待队列中, 根据返回值来判断是否可以跳出do_poll循环, 如果没有就绪且没有超时则该进程睡眠. 如果发生中断,在中断中要设置中断标志并唤醒睡眠的进程. 唤醒之后仍旧从do_poll的死循环开始执行, 再次执行了驱动中的 xxx_drv_poll, 而这时已经可读则顺利返回非0 mask值.  如果是超时则执行xxx_drv_poll仍旧无有效mask值, 可以但可以直接跳出do_poll循环, 应用程序根据不同的mask值做处理*/

以上就是linux驱动poll机制简要介绍是什么,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注行业资讯频道。

0