Linux嵌入式驱动学习之路按键驱动-poll机制

Posted 叶念西风

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux嵌入式驱动学习之路按键驱动-poll机制相关的知识,希望对你有一定的参考价值。

实现的功能是在读取按键信息的时候,如果没有产生按键,则程序休眠在read函数中,利用poll机制,可以在没有退出的情况下让程序自动退出。

下面的程序就是在读取按键信息的时候,如果5000ms内没有按键信息,则自己退出。

首先应用程序执行poll函数

    kernel中的sys_poll

            do_sys_poll

              init_poll_funcptr-->do_poll

            do_poll

              for(;;)

              {

                if(do_pollfd(pfd,pt))

                {  

                  count++;  //如果驱动的poll返回非0值,那么count++

                  //把进程挂到队列中休眠

                   pt=null;}

                if( count || !*timeout || signal_pending(current))

                  break; //如果count非0  超时, 有信号等待处理

              }

              __timeout = schedule_timeout(__time_out);  //休眠 下次执行到上面的判断时,就会超时退出

 

驱动代码:

#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
#include <linux/random.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/wait.h>
#include <linux/mutex.h>
#include <linux/io.h>
#include <asm/irq.h>
#include <linux/irq.h>
#include <linux/fs.h>
#include <asm/arch/regs-gpio.h>
#include <linux/interrupt.h>
#include <linux/poll.h>

static struct class *key_class;     //创建类
static struct class_device *key_class_devs;   //创建类对应的设备

struct pin_desc{
    unsigned int pin;
    unsigned int key_val;
};
struct pin_desc pins_desc[4] = {
    {S3C2410_GPF0,0X01},
    {S3C2410_GPF2,0X02},
    {S3C2410_GPG3,0X03},
    {S3C2410_GPG11,0X04},
};
unsigned char keyvals=0;

static volatile int ev_press = 0;
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);

static irqreturn_t keys_irq(int irq, void *dev_id)
{
    struct pin_desc *pindesc = (struct pin_desc *)dev_id;
    unsigned int pinval;
    pinval = s3c2410_gpio_getpin(pindesc->pin);
    if(pinval)
    {
        keyvals = pindesc->key_val|0x80;
    }
    else
    {
        keyvals = pindesc->key_val;
    }
    ev_press = 1;
    wake_up_interruptible(&button_waitq);
    return IRQ_HANDLED;
}


int key_open(struct inode *inode, struct file *fp)
{
    request_irq( IRQ_EINT0, keys_irq, IRQT_BOTHEDGE, "key2", &pins_desc[0]);
    request_irq( IRQ_EINT2, keys_irq, IRQT_BOTHEDGE, "key3", &pins_desc[1]);
    request_irq( IRQ_EINT11, keys_irq, IRQT_BOTHEDGE, "key4", &pins_desc[2]);
    request_irq( IRQ_EINT19, keys_irq, IRQT_BOTHEDGE, "key5", &pins_desc[3]);
    return 0;
}

ssize_t key_read(struct file *fp, char __user *buff, size_t count, loff_t *offp){

    if(count != 1)
    {
        return -EINVAL;
    }
    wait_event_interruptible(button_waitq,ev_press);
    
    copy_to_user(buff,&keyvals,1);
    ev_press = 0;
    return 0;
}

ssize_t key_write(struct file *fp, const char __user *buf, size_t count, loff_t *ppos){
}

int key_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]);
}

static unsigned int key_poll(struct file *file, struct poll_table_struct *wait)
{
    unsigned int mask = 0;
    poll_wait(file, &button_waitq,wait);
    if(ev_press)
        mask |= POLLIN|POLLRDNORM;
    return mask;
}

struct file_operations led_fops={
    .owner = THIS_MODULE,
    .open = key_open,
    .write  = key_write,
    .read   = key_read,
    .release = key_close,
    .poll = key_poll,
};

int major;
static int key_init(void)
{
    major = register_chrdev( 0,"key_drv", &led_fops );
    key_class = class_create(THIS_MODULE,"key_class");
    key_class_devs = class_device_create(key_class,NULL,MKDEV(major,0),NULL,"my_keys");
    
    printk("key install Module\n");
    return 0;
}

static void key_exit(void)
{
    unregister_chrdev( major, "key_drv" );
    class_device_unregister(key_class_devs);
    class_destroy(key_class);
    printk("key Module exit\n");
}

module_init(key_init);
module_exit(key_exit);
MODULE_LICENSE("GPL");

 

应用测试代码:

#include <stdio.h>
#include <fcntl.h>
#include <poll.h>

int main()
{
    int fd;
    int ret;
    struct pollfd pfd[1];
    unsigned char key_val;
    fd = open("/dev/my_keys",O_RDWR);
    if(fd<0)
    {
        printf("open failed\n");
        return 0;
    }
    pfd[0].fd = fd;
    pfd[0].events = POLLIN;
    while(1)
    {
        ret = poll(pfd, 1, 5000);    //如果在5000ms之内没有按下按键 这自动退出
//        read(fd, &key_val,1);
        if(ret==0)
            printf("time out\n");
        else
        {
            read(fd, &key_val,1);
            printf("key:%x\n",key_val);
        }
    }
}

 

 

sd

 

以上是关于Linux嵌入式驱动学习之路按键驱动-poll机制的主要内容,如果未能解决你的问题,请参考以下文章

Linux嵌入式驱动学习之路(十五)按键驱动-定时器防抖

Linux嵌入式驱动学习之路(二十一)字符设备驱动程序总结和块设备驱动程序的引入

linux驱动编写之poll机制

字符设备驱动按键poll机制

Linux嵌入式驱动学习之路(十六)输入子系统

Linux驱动入门Led驱动