多路復(fù)用 poll

  • 客戶端 app

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/input.h>
#include <poll.h>


struct key_event{
    int  code ; // 按鍵的鍵值, 比如KEY_DOWN,  KEY_POWER
    int value; // 按鍵的狀態(tài),按下為1, 抬起為0
};


int main(int argc, char *argv[])
{

    int fd;

    int ret;
    char kbbuf[128];
    struct key_event event;
    
    fd = open("/dev/key1", O_RDWR);
    if(fd < 0)
    {
        perror("open");
        exit(1);
    }

    struct pollfd pfd[2];

    pfd[0].fd = 0;  //監(jiān)控標(biāo)準(zhǔn)輸入          
    pfd[0].events = POLLIN;        
    
    pfd[1].fd = fd; //監(jiān)控按鍵                          //1.監(jiān)控對(duì)象
    pfd[1].events = POLLIN;                            //2.監(jiān)控模式

    while(1)
    {
            ret = poll(pfd, 2, -1);
            if(ret > 0)
            {
                if(pfd[0].revents & POLLIN)           //3.返回值(返回POLLIN時(shí)為真)
                {
                    fgets(kbbuf, 128, stdin);
                    printf("kbbuf = %s\n", kbbuf);
                }
                
                if(pfd[1].revents & POLLIN)          //3.返回值(返回POLLIN時(shí)為真)
                {
                    ret = read(fd, &event, sizeof(struct key_event));
                    if(ret < 0)
                    {
                        perror("read");
                        exit(1);
                    }

                    if(event.code == KEY_POWER)
                    {
                        if(event.value)
                        {
                            printf("__APP__ key power pressed\n");
                        }else
                        {
                            printf("__APP__ key power up\n");
                        }
                    }
                    if(event.code == KEY_ENTER)
                    {
                        if(event.value)
                        {
                            printf("__APP__ key enter pressed\n");
                        }else
                        {
                            printf("__APP__ key enter up\n");
                        }
                    }
                }
            }
    
        }

    close(fd);

    return 0;
}

  • 程序

要的

思想:


沒(méi)數(shù)據(jù)在VFS層等待,有數(shù)據(jù)返回POLLIN

口訣:有數(shù)據(jù)是返回POLLIN,沒(méi)數(shù)據(jù)返回0;

unsigned int key_drv_poll(struct file *filp, struct poll_table_struct *pts)
{
    printk("-------^_^   %s-----------\n", __FUNCTION__);
    unsigned int  mask = 0;
    
    // 將當(dāng)前的等待隊(duì)列注冊(cè)到vfs中
    poll_wait(filp, &key_dev->wq_head, pts);


    //如果有數(shù)據(jù)的時(shí)候,返回一個(gè)POLLIN
    if(key_dev->have_data)
            mask |= POLLIN;

    return mask;        //有數(shù)據(jù)是返回POLLIN,沒(méi)數(shù)據(jù)返回0;
}

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/poll.h>

#include <asm/uaccess.h>
#include <asm/io.h>


// 設(shè)計(jì)一個(gè)表示按鍵數(shù)據(jù)的對(duì)象
struct key_event{
    int  code ; // 按鍵的鍵值, 比如KEY_DOWN,  KEY_POWER
    int value; // 按鍵的狀態(tài),按下為1, 抬起為0
};

// 面向?qū)ο?--將任何都看成對(duì)象, struct 就是對(duì)象
//設(shè)計(jì)一個(gè)對(duì)象類(lèi)型,描述當(dāng)前的設(shè)備信息,同時(shí)是一個(gè)全局的設(shè)備對(duì)象
struct s5pv210_key{
    int dev_major; //用老的注冊(cè)設(shè)備號(hào)的方式
    struct class *cls;
    struct device *dev;
    int irqno; //表示設(shè)備的中斷號(hào)碼
    int testdata;
    struct key_event event;//存放按鍵的數(shù)據(jù)
    wait_queue_head_t wq_head;
    int have_data; //表示標(biāo)志位,表示是否有數(shù)據(jù)
};

//設(shè)計(jì)一個(gè)對(duì)象,描述是按鍵的信息
/*
1, 中斷號(hào)
    2, gpio號(hào)碼
    3, 名字
    4, 按鍵的類(lèi)型
*/
struct key_info{
    char *name;
    int irqno;
    int gpionum;
    int code;
    int flags;  //觸發(fā)方式
};
//設(shè)置所有按鍵的信息
struct key_info  allkeys[] = {
    [0] = {
        .name = "key1_eint0",        // 中斷名字
        .irqno = IRQ_EINT(0),         //  中斷號(hào)
        .gpionum = S5PV210_GPH0(0),     //gpio腳
        .flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,  //上下沿觸發(fā)(觸發(fā)方式)
        .code = KEY_UP,    //當(dāng)前的按鍵(上下左右)
    },

    [1] = {
        .name = "key2_eint1",
        .irqno = IRQ_EINT(1),
        .gpionum = S5PV210_GPH0(1),
        .flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
        .code = KEY_DOWN,
    },
    [2] = {
        .name = "key3_eint2",
        .irqno = IRQ_EINT(2),
        .gpionum = S5PV210_GPH0(2),
        .flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
        .code = KEY_LEFT,
    },
    [3] = {
        .name = "key4_eint3",
        .irqno = IRQ_EINT(3),
        .gpionum = S5PV210_GPH0(3),
        .flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
        .code = KEY_RIGHT,

    },

    [4] = {
        .name = "key5_eint4",
        .irqno = IRQ_EINT(4),
        .gpionum = S5PV210_GPH0(4),
        .flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
        .code = KEY_ENTER,

    },
    [5] = {
        .name = "key6_eint5",
        .irqno = IRQ_EINT(5),
        .gpionum = S5PV210_GPH0(5),
        .flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
        .code = KEY_ESC,

    },
    [6] = {
        .name = "key7_eint22",
        .irqno = IRQ_EINT16_31,
        .gpionum = S5PV210_GPH2(6),
        .flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
        .code = KEY_HOME,

    },
    [7] = {
        .name = "key8_eint23",
        .irqno = IRQ_EINT16_31,
        .gpionum = S5PV210_GPH2(7),
        .flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
        .code = KEY_POWER,
    },
};




//設(shè)置對(duì)象
struct  s5pv210_key  *key_dev;



int key_drv_open(struct inode *inode, struct file *filp)
{
    //一般也是做初始化動(dòng)作
    printk("-------^_^   %s-----------\n", __FUNCTION__);

    memset(&key_dev->event,0, sizeof(struct key_event));
    key_dev->have_data = 0;

    return 0;

}

// write(fd, buf, size);
ssize_t key_drv_write(struct file *filp, const char __user *buf, size_t count, loff_t *fpos)
{


    return 0;

}
int key_drv_close(struct inode *inode, struct file *filp)
{
    printk("-------^_^   %s-----------\n", __FUNCTION__);


    return 0;

}


long key_drv_ioctl(struct file *filp, unsigned int cmd, unsigned long args)
{

    
    return 0;

}


ssize_t key_drv_read (struct file *filp, char __user *buf, size_t count, loff_t *fpos)
{
    //printk("-------^_^   %s-----------\n", __FUNCTION__);
    int ret;

    //區(qū)分阻塞還是非阻塞
    if((filp->f_flags & O_NONBLOCK ) &&  !key_dev->have_data)
        return -EAGAIN;

    
    // 沒(méi)有數(shù)據(jù)就休眠--have_data如果0表示沒(méi)有數(shù)據(jù),就需要等
    wait_event_interruptible(key_dev->wq_head, key_dev->have_data);

    ret = copy_to_user(buf, &key_dev->event, count);
    if(ret > 0)
    {
        printk("copy_to_user error\n");
        return -EFAULT;
    }

    // 清空后,接著去收其他的數(shù)據(jù)
    memset(&key_dev->event,0, sizeof(struct key_event));
    key_dev->have_data = 0; // 重新設(shè)置成沒(méi)有數(shù)據(jù)

    
    return count;

}


unsigned int key_drv_poll(struct file *filp, struct poll_table_struct *pts)
{
    printk("-------^_^   %s-----------\n", __FUNCTION__);
    unsigned int  mask = 0;
    
    // 將當(dāng)前的等待隊(duì)列注冊(cè)到vfs中
    poll_wait(filp, &key_dev->wq_head, pts);


    //如果有數(shù)據(jù)的時(shí)候,返回一個(gè)POLLIN
    if(key_dev->have_data)
            mask |= POLLIN;

    return mask;        //有數(shù)據(jù)是返回POLLIN,沒(méi)數(shù)據(jù)返回0;
}


const struct file_operations  key_fops = {
    .open = key_drv_open,
    .write = key_drv_write,
    .read = key_drv_read,
    .release = key_drv_close,
    .unlocked_ioctl = key_drv_ioctl,
    .poll = key_drv_poll,
};



irqreturn_t key_irq_handler(int irqno, void *dev_id)
{

    printk("-------^_^   %s-----------\n", __FUNCTION__);

    //區(qū)分不同的中斷
    struct key_info  *p = (struct key_info  *)dev_id;

    //區(qū)分是按下還是抬起
    int value;


    value = gpio_get_value(p->gpionum);
    
    if(value){
        //抬起
        printk("%s  up \n", p->name);
        key_dev->event.code = p->code;
        key_dev->event.value = 0;

    }else{
        //按下    
        printk("%s  pressed \n", p->name);
        key_dev->event.code =  p->code;
        key_dev->event.value = 1;
    }

    wake_up_interruptible(&key_dev->wq_head);//會(huì)喚醒
    key_dev->have_data = 1; //表示有數(shù)據(jù)

    
    return IRQ_HANDLED;
}



static  int __init key_drv_init(void)
{
    int ret;
    //申請(qǐng)資源
    // 實(shí)例化該對(duì)象
    //  GFP_KERNEL如果當(dāng)前沒(méi)有內(nèi)存可分配,該函數(shù)會(huì)一直等
    key_dev = kzalloc(sizeof(struct s5pv210_key), GFP_KERNEL);
    if(key_dev == NULL)
    {
        printk(KERN_ERR "kzalloc error\n");
        return -ENOMEM;
    }
    // 1,  申請(qǐng)?jiān)O(shè)備號(hào)
    key_dev->dev_major = register_chrdev(0, "s5pv210_key_drv", &key_fops);
    if(key_dev->dev_major < 0)
    {
        printk(KERN_ERR "kzalloc error\n");
        ret = -ENODEV;
        goto err_0;
    }

    
    // 2, 自動(dòng)創(chuàng)建文件
    //  /sys/class/key_cls 文件夾
    key_dev->cls = class_create(THIS_MODULE, "key_cls");
    if(IS_ERR(key_dev->cls))
    {
        printk(KERN_ERR "class_create error\n");
        ret = PTR_ERR(key_dev->cls);
        goto err_1;
    }

    //  /sys/class/key_cls/key/
    //  /dev/key1
    key_dev->dev = device_create(key_dev->cls, NULL, MKDEV(key_dev->dev_major,1),NULL, "key1");
    if(IS_ERR(key_dev->dev))
    {
        printk(KERN_ERR "device_create error\n");
        ret = PTR_ERR(key_dev->dev);
        goto err_2;
    }


    // 4, 硬件的初始化---中斷
    //
    //key_dev->irqno = IRQ_EINT(1);

    int i;
    int irqno;
    int flags;
    char *name;
    for(i=0; i<ARRAY_SIZE(allkeys); i++)
    {
        irqno = allkeys[i].irqno;
        if(irqno == IRQ_EINT16_31)
                irqno = gpio_to_irq(allkeys[i].gpionum);

        flags = allkeys[i].flags;
        name = allkeys[i].name;

               //    1.   中斷號(hào)  中斷處理函數(shù)  觸發(fā)方式  中斷名字 傳遞給處理函數(shù)的值                        
        ret = request_irq(irqno, key_irq_handler, flags,name, &allkeys[i]);   //中斷申請(qǐng)
        if(ret != 0)
        {
            printk(KERN_ERR "request_irq error  : i=%d\n", i);
            ret = -EBUSY;
            goto err_4;
        }
        
    }
    
    //初始化等待隊(duì)列頭
    init_waitqueue_head(&key_dev->wq_head);
    
    return 0;

err_4:
    i--;
    for(; i>0; i--)
    {
        irqno = gpio_to_irq(allkeys[i].gpionum);
        free_irq(irqno, &allkeys[i]);
    }
    
err_3:
    device_destroy(key_dev->cls, MKDEV(key_dev->dev_major,1));
err_2:
    class_destroy(key_dev->cls);

err_1:
    unregister_chrdev(key_dev->dev_major, "s5pv210_key_drv");
    
err_0:
    kfree(key_dev);
    return ret;

}


static void __exit  key_drv_exit(void)
{
    //釋放資源
    int i;
    int irqno;
    for(i=0; i<ARRAY_SIZE(allkeys); i++)
    {   
        irqno = gpio_to_irq(allkeys[i].gpionum);
        free_irq(irqno, &allkeys[i]);
    }
    device_destroy(key_dev->cls, MKDEV(key_dev->dev_major,1));
    class_destroy(key_dev->cls);
    unregister_chrdev(key_dev->dev_major, "s5pv210_key_drv");
    
    kfree(key_dev);
}



module_init(key_drv_init);
module_exit(key_drv_exit);
MODULE_LICENSE("GPL");

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容