单片机
返回首页

字符设备驱动程序之poll机制

2016-04-01 来源:eefocus

驱动源码:
#include 'linux/module.h'
#include 'linux/kernel.h'
#include 'linux/fs.h'
#include 'linux/init.h'
#include 'linux/delay.h'
#include 'linux/irq.h'
#include 'asm/uaccess.h'
#include 'asm/irq.h'
#include 'asm/io.h'
#include 'asm/arch/regs-gpio.h'
#include 'asm/hardware.h'
#include 'linux/poll.h'
 
int major = 0;
static struct class *keydrv_class;
static struct class_device *keydrv_class_dev;
volatile unsigned long *gpfcon;
volatile unsigned long *gpfdat;
 
volatile unsigned long *gpgcon;
volatile unsigned long *gpgdat;
 
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},
};
 
// 键值: 按下时, 0x01, 0x02, 0x03, 0x04 
// 键值: 松开时, 0x81, 0x82, 0x83, 0x84 
static unsigned char key_val;
 
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
 
// 中断事件标志, 中断服务程序将它置1,third_drv_read将它清0 
static volatile int ev_press = 0;
 
static irqreturn_t buttons_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)
    {
        // 松开 
        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 key_drv_open(struct inode *inode, struct file *file)
{
    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 key_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
    if(size != sizeof(key_val))
        return -EINVAL;
    
    // 如果没有按键动作, 休眠  
    wait_event_interruptible(button_waitq, ev_press);
 
    // 如果有按键动作, 返回键值  
    copy_to_user(buf, &key_val, 1);
    
    ev_press = 0;
    
    return 1;
}
 
int key_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 key_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 key_drv_fops = {
    .owner   =   THIS_MODULE,    // 这是一个宏,推向编译模块时自动创建的__this_module变量  
    .open    =   key_drv_open,     
    .read    = key_drv_read,
    .release =   key_drv_close,
    .poll    =   key_drv_poll,
};
 
static int key_drv_init(void)
{
    major = register_chrdev(0, 'key_drv', &key_drv_fops);
 
    keydrv_class = class_create(THIS_MODULE, 'key_drv');
    
    keydrv_class_dev = class_device_create(keydrv_class, NULL, MKDEV(major, 0), NULL, '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 key_drv_exit(void)
{
    unregister_chrdev(major, 'key_drv');
    class_device_unregister(keydrv_class_dev);
    class_destroy(keydrv_class);
    iounmap(gpfcon);
    iounmap(gpgcon);
    return 0;    
}
 
 
module_init(key_drv_init);
 
module_exit(key_drv_exit);
 
MODULE_LICENSE('GPL');
 
=================================================================
测试源码:
#include
#include
#include
#include
#include
 
int main(int argc, char **argv)
{
    int fd;
    unsigned char key_vals;
 
    int ret;
    struct pollfd fds[1];
 
    fd = open('/dev/buttons', O_RDWR);
    if(fd < 0)
        printf('can't open!\n');
 
    fds[0].fd = fd;
    fds[0].events = POLLIN;
    while(1)
    {
        ret = poll(fds, 1, 5000);    //5000是毫秒为单位,等待5S钟判断fds[0].fd文件是否有新数据可读
        if(ret == 0)
        {
            printf('time out !\n');  //超时   
        }
        else
        {
            read(fd, &key_vals, 1);  //有数据可读
            printf('key_vals = 0x%x\n', key_vals);
        }
    }
    return 0;
}
==================================================================
解析:
1、key_drv_fops 结构体中增加:.poll    =   key_drv_poll,
      key_drv_poll函数就去查询有没有按键值更新(/dev/buttons),如果按键按下则返回,否则休眠,等到休眠时间到则自动返回;
2、应用程序中循环调用poll函数,判断按键值有没有更新;如果更新则读取,否则超时提醒。


进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • PIC单片机控制的遥控防盗报警器电路

  • 红外线探测报警器

  • 短波AM发射器电路设计图

  • 使用ESP8266从NTP服务器获取时间并在OLED显示器上显示

  • 开关电源的基本组成及工作原理

  • 带有短路保护系统的5V直流稳压电源电路图

    相关电子头条文章