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

发布者:CW13236066525最新更新时间:2016-04-01 来源: eefocus关键字:字符设备  驱动程序  poll机制 手机看文章 扫描二维码
随时随地手机看文章
驱动源码:
#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函数,判断按键值有没有更新;如果更新则读取,否则超时提醒。


关键字:字符设备  驱动程序  poll机制 引用地址:字符设备驱动程序之poll机制

上一篇:字符设备驱动程序之异步通知
下一篇:字符设备驱动-高级篇按键中断程序驱动

推荐阅读最新更新时间:2024-03-16 14:49

典型的Linux设备驱动程序的代码
为了增跟内核的灵活性和为了方便,设各驱动程序应被设计为一个可动态安装的内核模块。 于是,一个典型的Linux设备驱动程序应包含如下几部分代码: ·驱动程序模块的注册与注销函数; ·设各的打开、关闭、读、写及需要的其他操作函数; ·设备的中断服务程序。 下面用伪代码给出一个从键盘上输入一个字符的例子,以使读者对设备驱动程序的构成有一个基本的概念。 (1)定义读操作函数 ssize mydev_read(……) { 获取本设备的信号量以确倮没有其他进程访闷本设备; 申请中断标志,允许中断; 对设备发出读命令; 将进EH于等待队列,等待中断到来: } (2)定义中断服务程序
[单片机]
基于嵌入式Linux系统设备驱动程序的开发
引言 Linux是一个遵循POSIX标准的免费操作系统。具有BSD和SYSV的扩展特性。与其他操作系统相比,嵌入式Linux系统以其可应用于多种硬件平台、内核高效稳定、源码开放、软件丰富、网络通信和文件管理机制完善等优良特性而正被作为研究热点,越来越多的研究人员采用Linux平台来开发自己的产品。Linux设备驱动程序在Linux内核源代码中占有很大比例,从2.0、2.2到 2.4版本的内核,源代码的长度日益增加,其实主要是设备驱动程序在增加。 设备驱动程序的编写 设备驱动程序是linux内核的一部分,是操作系统内核和机器硬件之间的接口,它由一组函数和一些私有数据组成,是连接应用程序与具体硬件的桥梁。Linux的一个基本特点是它
[单片机]
嵌入式Linux网络驱动程序的开发及实现原理
   0 引言   随着人们对开放源代码软件热情的日益增高,Linux作为一个功能强大而稳定的开源操作系统,越来越受到成千上万的计算机专家和爱好者的青睐。在嵌入式领域,通过对Linux进行小型化裁剪后,使其能够固化在容量只有几十兆字节的存储器芯片或单片机中,成为应用于特定场合的嵌入式Linux系统。Linux强大的网络支持功能实现了对包括TCP/IP在内的多种协议的支持,满足了面向21世纪的嵌入式系统应用联网的需求。因此,在嵌入式系统开发调试时,网络接口几乎成为不可或缺的模块。    1 嵌入式Linux网络驱动程序介绍   Linux网络驱动程序作为Linux网络子系统的一部分,位于TCP/IP网络体系结构的网络接口
[嵌入式]
基于Windows CE的SPI驱动程序设计
引 言   Windows CE为支持多线程、多任务、抢占式的嵌入式操作系统。随着Windows CE 6.0的发布,其内核性能的明显提升和源代码开放,将促使其在消费电子、工业控制、移动通信等领域得到广泛的应用。通常Platform Builder中给出了支持多种CPU常用设备驱动程序,如LCD驱动、鼠标驱动、USB驱动、串口驱动等;但有时由于平台采用了其他特定的硬件设备,其驱动程序在Platform Builder并没有给出,这时就需要用户针对实际的硬件自行开发,以满足个性化的需求。本文所涉及的SPI接口驱动就属于此类。 1 SPI总线及S3C2440芯片介绍   串行外围设备接口SPI(Serial Peripheral I
[单片机]
基于Windows CE的SPI<font color='red'>驱动程序</font>设计
stm32-esp8266驱动程序
esp8266模块是串口通讯,通讯的协议是AT指令,要正确的配置对应的AT指令模块才可以工作,这里就需要知道AT指令有没有配置成功,这个比较容易实现,一般发送AT指令配置成功的话,芯片都会返回至少一个OK,当然还有其它数据,我们只需要去解析有没有接收到OK就知道指令发送是否成功了。我这里是作为TCP客服端,所以只需要以下一些指令即可: 1 发送 ATrn 返回 OK 以上操作确保芯片连接正常,工作正常 2 发送 ATE0rn 返回 OK 关闭回显 3 发送 AT+CWMODE=1rn 返回 OK 设置成客服端模式 4 发送 AT+CIPSTATUS 返回 2 3 4 5 2
[单片机]
stm32-esp8266<font color='red'>驱动程序</font>
STM32开发笔记87: SX1268驱动程序设计(设置为STDBY模式)
单片机型号:STM32L053R8T6 本系列开发日志,将详述SX1268驱动程序的整个设计过程,本篇介绍将芯片设置为STDBY模式的相关驱动程序。 一、STDBY模式 芯片上电、复位和从睡眠模式唤醒,都会从Startup模式自动进入到STDBY模式。STDBY模式又称为待机模式或者旁路模式。 在待机模式下,主机应在进入RX或TX模式之前配置芯片。默认情况下,系统选择13MHZ的RC振荡器,以降低功耗。除睡眠模式外,其它模式XTAL时钟处于打开状态。然而,只有在应用程序对时钟要求严格,我们才需要打开XOSX模块,并让它始终处于打开状态。 待机模式下的XOSC或RC13M选择由命令SetStandby(…)中的模式参
[单片机]
STM32开发笔记87: SX1268<font color='red'>驱动程序</font>设计(设置为STDBY模式)
基于嵌入式Linux 的I2C设备驱动程序的分析
  0 引言   由于I2C总线的通用性,Linux作为一款优秀的嵌入式操作系统,也必须要对其要有很好的支持。在Linux内核源码中对I2C总线的驱动是基于总线设备驱动模型的,其驱动程序用到了特殊的几个数据结构,对I2C总线协议进行了更抽象更通用的定义,极大的增加了设备驱动的可移植性。要编写出自己的I2C 设备驱动程序,必须对这种内核I2C总线驱动的架构有深刻的理解。   1 I2C总线的硬件构成   I2C 总线协议只有两条总线线路,一条是串行数据线(SDA),一条是串行时钟线(SCL)。SDA 负责数据的传输,SCL 负责数据传输的时钟同步。I2C 设备通过这两条总线连接到处理器的I2C总线控制器上,不同设备之间通过7
[单片机]
基于嵌入式Linux 的I2C<font color='red'>设备</font><font color='red'>驱动程序</font>的分析
μC/OS-II实时内核下的A/D驱动程序设计
摘要:详细分析在μC/OS-II实时内核下驱动程序读取A/D的三种方法;阐述C8051F015单片机的A/D转换器的配置、转换特点及其驱动程序读取A/D采用的方法;针对C8051F015单片机分析A/D驱动程序设计的方法和思想。这些方法和思想为在μC/OS-II下访问其它类型的A/D提供了很好的借鉴。 关键词:μC/OS-II A/D 驱动程序 C8051F015 A/D转换是单片机数据采集系统的重要组成部分,实时内核下A/D驱动程序的实现过程主取决于A/D转换器的转换时间。本文首先比较和分析μC/OS-II下A/D采样数据的三种方法;其次介绍C8051F015单片机A/D模数转换器配置及特点;最后,在μC/OS-II内核移
[嵌入式]
热门资源推荐
热门放大器推荐
  •  pdf文件现代操作系统(原书第4版)
  •  pdf文件机器视觉技术 (陈兵旗)
  •  rar文件adxl372驱动程序
  •  pdf文件电脑世界的通关密语:电脑编程基础 (杉浦贤)
  • 系统发生错误

    系统发生错误

    您可以选择 [ 重试 ] [ 返回 ] 或者 [ 回到首页 ]

    [ 错误信息 ]

    页面错误!请稍后再试~

小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
  • 学习ARM开发(16)
    ARM有很多东西要学习,那么中断,就肯定是需要学习的东西。自从CPU引入中断以来,才真正地进入多任务系统工作,并且大大提高了工作效率。采 ...
  • 学习ARM开发(17)
    因为嵌入式系统里全部要使用中断的,那么我的S3C44B0怎么样中断流程呢?那我就需要了解整个流程了。要深入了解,最好的方法,就是去写程序 ...
  • 学习ARM开发(18)
    上一次已经了解ARM的中断处理过程,并且可以设置中断函数,那么它这样就可以工作了吗?答案是否定的。因为S3C44B0还有好几个寄存器是控制中 ...
  • 嵌入式系统调试仿真工具
    嵌入式硬件系统设计出来后就要进行调试,不管是硬件调试还是软件调试或者程序固化,都需要用到调试仿真工具。 随着处理器新品种、新 ...
  • 最近困扰在心中的一个小疑问终于解惑了~~
    最近在驱动方面一直在概念上不能很好的理解 有时候结合别人写的一点usb的例子能有点感觉,但是因为arm体系里面没有像单片机那样直接讲解引脚 ...
  • 学习ARM开发(1)
  • 学习ARM开发(2)
  • 学习ARM开发(4)
  • 学习ARM开发(6)
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved