代码示例_poll的多路复用

发布者:DazzlingSmile最新更新时间:2025-02-06 来源: cnblogs关键字:多路复用  S5PV210 手机看文章 扫描二维码
随时随地手机看文章

//头文件

#include <linux/init.h>

#include

#include

#include

#include

#include gpio.h>

#include

#include

#include

#include

#include


#include

#include

#include

#include


//定义一个按键的数据包

struct button_event{

    int code;         //按键的名称---键值:KEY_DOWN

    int value;        //按键的状态---按下:1,松开:0

};


//设计一个描述按键的结构体类型

struct buttons{

    char *name;        //名称

    unsigned int irqno;        //中断号

    int gpio;                //按键对应的gpio口

    int code;                //键值

    unsigned long flags;    //触发方式

};


//定义一个数组来保存多个按键的数据

struct buttons buttons_set[] = {

    [0] = {

        .name = 'key1_up',

        .irqno = IRQ_EINT(0),

        .gpio = S5PV210_GPH0(0),

        .code = KEY_UP,

        .flags = IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,

    },

    [1] = {

        .name = 'key2_down',

        .irqno = IRQ_EINT(1),

        .gpio = S5PV210_GPH0(1),

        .code = KEY_DOWN,

        .flags = IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,

    },

    [2] = {

        .name = 'key3_left',

        .irqno = IRQ_EINT(2),

        .gpio = S5PV210_GPH0(2),

        .code = KEY_LEFT,

        .flags = IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,

    },

    [3] = {

        .name = 'key4_right',

        .irqno = IRQ_EINT(3),

        .gpio = S5PV210_GPH0(3),

        .code = KEY_RIGHT,

        .flags = IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,

    },

};


//面向对象编程----设计设备的类型

struct s5pv210_button{

    //unsigned int major;

    dev_t  devno;

    struct class * cls;

    struct device * dev;

    struct cdev  *cdev;

    unsigned int irqno;

    struct button_event event;

    wait_queue_head_t wq_head;

    

    int have_data;        //表示当前是否有数据可读,可读--1,不可读--0

};

struct s5pv210_button *button_dev;


//实现中断处理函数--------当触发中断时会被执行

irqreturn_t button_irq_svc(int irqno, void *dev)

{

    int value;

    struct buttons *p;

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


    //获取当前触发中断的按键信息

    p = (struct buttons *)dev;

    

    //获取产生中断的gpio口的值

    value = gpio_get_value(p->gpio);

    //判断是按下还是松开

    if(value){

        //松开

        printk('kernel:%s up!n',p->name);

        button_dev->event.code = p->code;

        button_dev->event.value = 0;

    }else{

        //按下

        printk('kenel:%s pressed!n',p->name);

        button_dev->event.code = p->code;

        button_dev->event.value = 1;

    }


    //此时有数据可读

    button_dev->have_data = 1;


    //从等待队列中唤醒阻塞的进程

    wake_up_interruptible(&button_dev->wq_head);

    

    return IRQ_HANDLED;

}


//实现设备操作接口

int button_open(struct inode *inode, struct file *filp)

{


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

    

    return 0;

}

ssize_t button_read(struct file *filp , char __user *buf , size_t size, loff_t *flags)

{

    int ret;

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

    //判读open时,有没有设置flags为NONBLOCK

    if(filp->f_flags & O_NONBLOCK && !button_dev->have_data)

        return -EAGAIN;

        

    //判断此时是否有数据可读

    wait_event_interruptible(button_dev->wq_head,button_dev->have_data);

    

    //将内核数据转换为用户空间数据

    ret = copy_to_user(buf,&button_dev->event,size);

    if(ret > 0){

        printk('copy_to_user error!n');

        return -EFAULT;

    }


    //将数据返回给应用空间后,清空数据包,同时将hava_data置零

    memset(&button_dev->event,0,sizeof(button_dev->event));

    button_dev->have_data = 0;

    return size;

}


ssize_t button_write(struct file *filp, const char __user *buf, size_t size, loff_t *flags)

{


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


    return size;

}


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

{

    

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

    

    return 0;

}

unsigned int button_poll(struct file *filp, struct poll_table_struct *pts)

{

    unsigned int mask = 0;

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


    //1,将等待队列头注册到系统中(VFS)

    poll_wait(filp,&button_dev->wq_head,pts);


    //2,如果产生按键中断-有数据可读,此时返回POLLIN,如果没有数据返回0

    if(button_dev->have_data)

        mask |= POLLIN;


    return mask;

    

}


int button_close(struct inode *inode, struct file *filp)

{

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

    

    return 0;

}



static struct file_operations fops = {

    .open = button_open,

    .read = button_read,

    .write = button_write,

    .poll = button_poll,

    .unlocked_ioctl = button_ioctl,

    .release = button_close,

};



//加载函数和卸载函数

static int __init button_init(void)   //加载函数-----在驱动被加载时执行

{

    int ret,i;

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

    //0,实例化设备对象

    //参数1 ---- 要申请的空间的大小

    //参数2 ---- 申请的空间的标识

    button_dev = kzalloc(sizeof(struct s5pv210_button),GFP_KERNEL);

    if(IS_ERR(button_dev)){

        printk('kzalloc error!n');

        ret = PTR_ERR(button_dev);

        return -ENOMEM;

    }

    

    //1,申请设备号-----新方法

#if 0

    //静态申请设备号

    button_dev->major = 256;

    ret = register_chrdev_region(MKDEV(button_dev->major,0),1,'button_drv');

    if(ret < 0){

        printk('register_chrdev_region error!n');

        ret =  -EINVAL;

        goto err_kfree;

    }

#else

    //动态申请设备号

    ret = alloc_chrdev_region(&button_dev->devno,0,1,'button_drv');

    if(ret < 0){

        printk('register_chrdev_region error!n');

        ret =  -EINVAL;

        goto err_kfree;

    }

#endif


    //创建cdev


    //申请cdev的空间

    button_dev->cdev = cdev_alloc();

    if(IS_ERR(button_dev->cdev)){        

        printk('button_dev->cdev error!n');

        ret = PTR_ERR(button_dev->cdev);

        goto err_unregister;

    }


    //初始化cdev的成员

    cdev_init(button_dev->cdev,&fops);


    //将cdev加入到内核中----链表

    ret = cdev_add(button_dev->cdev,button_dev->devno,1);



    

    //2,创建设备文件-----/dev/button

    button_dev->cls = class_create(THIS_MODULE,'button_cls');

    if(IS_ERR(button_dev->cls)){

        printk('class_create error!n');

        ret = PTR_ERR(button_dev->cls);

        goto err_cdev_del;

    }

    

    button_dev->dev = device_create(button_dev->cls,NULL,button_dev->devno,NULL,'button');

    if(IS_ERR(button_dev->dev)){

        printk('device_create error!n');

        ret = PTR_ERR(button_dev->dev);

        goto err_class;

    }



    //3,硬件初始化---申请中断

    for(i = 0; i < ARRAY_SIZE(buttons_set);i++){

        ret = request_irq(buttons_set[i].irqno,button_irq_svc,buttons_set[i].flags,buttons_set[i].name,&buttons_set[i]);

        if(ret != 0){

            printk('request_irq error!n');

            ret = -EBUSY;

            goto err_device;

        }

    }

    //初始化等待队列头

    init_waitqueue_head(&button_dev->wq_head);

    


    return 0;

    

err_device:

    device_destroy(button_dev->cls,button_dev->devno);

err_class:

    class_destroy(button_dev->cls);

    

err_cdev_del:

    cdev_del(button_dev->cdev);

    

err_unregister:

    unregister_chrdev_region(button_dev->devno,1);

    

err_kfree:

    kfree(button_dev);

    return ret;


    

}


static void __exit button_exit(void)   //卸载函数-----在驱动被卸载时执行

{

    int i;

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

[1] [2]
关键字:多路复用  S5PV210 引用地址:代码示例_poll的多路复用

上一篇:内核提供的读写寄存器接口实现可移植性
下一篇:ARM—配置交叉编译环境

推荐阅读最新更新时间:2026-03-20 11:35

代码示例_poll多路复用
//头文件 #include linux/init.h #include linux/module.h #include linux/fs.h #include linux/device.h #include linux/slab.h #include linux/gpio.h #include linux/cdev.h #include linux/interrupt.h #include linux/input.h #include linux/sched.h #include linux/poll.h #include asm/io.h #include asm/string.h #include
[单片机]
Linux驱动入门(六)poll机制实现按键驱动
一、poll应用编程 二、驱动poll机制的实现 三、源码 四、测试 如何使用read阻塞去读取按键驱动,那么就意味着一个线程只能监听一个按键,如果想要监听多个按键,就需要启动多个线程,开启线程会耗费资源,并且多线程会增加编程难度,那么有没有一种机制,使得一个线程可以监听多路IO呢? Linux提供的select、poll、epoll机制,select、poll、epoll可以监听多路IO的状态,直到有IO满足条件(可读或可写等)时返回 其中select、poll系统调用的实现原理是类似的,epoll有别于这两者 但是对于底层驱动的实现都是一样的,都是实现驱动的poll函数 本文将介绍如何实现一个支持多路IO复用的驱动程序 一、p
[单片机]
S3C2440 开发板实战(9):poll机制
内核:linux -2.6.22.6 内核执行poll过程 从代码的角度来看,poll机制是通过应用程序调用poll() 函数,poll()函数的使用方法可以通过man poll进行查看,可仿照最终程序中进行改写,这里不做重复说明。配合驱动函数中相对应的drv_poll() 函数配套使用的。函数执行的入口当然是应用程序中的poll()函数,接着进入内核中的sys_poll() 函数,poll机制的函数在路经:linux/fs/select.c下,原代码如下: 739 asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds, 740
[单片机]
S3C2440 开发板实战(9):<font color='red'>poll</font>机制
Tiny210驱动之按键poll机制
forth_drv.c驱动源码: #include linux/device.h #include linux/interrupt.h #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 mach/gpio.h #include linux/poll.h s
[单片机]
字符设备驱动程序之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; st
[单片机]
字符设备驱动程序之<font color='red'>poll</font>机制
(一)S5PV210开发板常用易忘操作记录
一、调试串口 2、SD卡槽 (三)启动方式选择 蜂鸣器下面的白色2针插座(图中红色线圈出来的那个)为选择USB/SD卡启动的开关。默认情况下为SD卡启动,如果需要USB启动则使用短路帽(若没有短路帽,只要用其他金属导电物短路2根针即可)短接2个针脚,即可从USB启动。 (四)刷机 注意:刷andorid4.0系统使用uart2作为调试串口,android2.3、linux、wince都使用uart0作为调试串口;然后波特率设置为115200 用 fastboot 刷Android4.0: 用的镜像文件: uboot.bin、x210.img、zImage-android 用到的工具: DNW.exe fa
[单片机]
(一)<font color='red'>S5PV210</font>开发板常用易忘操作记录
S5PV210 点亮Led
GPC1CON, R/W, Address = 0xE020_0080 GPC1DAT, R/W, Address = 0xE020_0084 举例 #define GPC1CON *((volatile unsigned int*)0xE0200080) #define GPC1DAT *((volatile unsigned int*)0xE0200084) *(unsigned int*)GPC1CON &= ~(0xf 12); *(unsigned int*)GPC1CON |= (0x1 12); *(unsigned int*)GPC1DAT &= ~(0x1 3); *(un
[单片机]
<font color='red'>S5PV210</font> 点亮Led
基于s5pv210的uboot总结
1、启动过程特征总结   (1)第一阶段为汇编阶段、第二阶段为C阶段   (2)第一阶段在SRAM中、第二阶段在DRAM中   (3)第一阶段注重SoC内部、第二阶段注重SoC外部Board内部 2、uboot的第一阶段做了哪些工作   (1)构建异常向量表   (2)设置CPU为SVC模式   (3)关看门狗   (4)开发板供电置锁   (5)时钟初始化   (6)DDR初始化   (7)串口初始化并打印 OK   (8)重定位   (9)建立映射表并开启MMU   (10)跳转到第二阶段 3、uboot第二阶段主要是对开发板级别的硬件、软件数据结构进行初始化。   init_sequence   cpu_init 空的   
[单片机]
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

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

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved