代码示例_非阻塞IO

发布者:genius5最新更新时间:2025-02-08 来源: cnblogs关键字:非阻塞IO  s5pv210 手机看文章 扫描二维码
随时随地手机看文章

//头文件

#include <linux/init.h>

#include

#include

#include

#include

#include gpio.h>

#include

#include

#include

#include




#include

#include

#include

#include


#define LED_NUM_ON        _IOW('L',0x1122,int)

#define LED_NUM_OFF        _IOW('L',0x3344,int)

#define LED_ALL_ON        _IO('L',0x1234)

#define LED_ALL_OFF        _IO('L',0x5678)


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

struct button_event{

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

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

};



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

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;

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

    //获取按键信息

    value = gpio_get_value(S5PV210_GPH0(1));

    //判断是按下还是松开

    if(value){

        //松开

        printk('kenel:keydown up!n');

        button_dev->event.code = KEY_DOWN;

        button_dev->event.value = 0;

    }else{

        //按下

        printk('kenel:keydown pressed!n');

        button_dev->event.code = KEY_DOWN;

        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;

}


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,

    .unlocked_ioctl = button_ioctl,

    .release = button_close,

};



//加载函数和卸载函数

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

{

    int ret;

    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,硬件初始化---申请中断

    button_dev->irqno = IRQ_EINT(1);

    ret = request_irq(button_dev->irqno,button_irq_svc,IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,'eint-keydown',NULL);

    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)   //卸载函数-----在驱动被卸载时执行

{

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

    free_irq(button_dev->irqno,NULL);

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

    class_destroy(button_dev->cls);

    cdev_del(button_dev->cdev);

    unregister_chrdev_region(button_dev->devno,1);

    kfree(button_dev);

}


//声明和认证

module_init(button_init);

module_exit(button_exit);

MODULE_LICENSE('GPL');


#include

#include

#include

#include

#include

#include

#include

#include

#include


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

struct button_event{

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

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

};


int main(void)

{


    int fd;

    int ret;

    struct button_event event;


    //fd = open('/dev/button',O_RDWR|O_NONBLOCK);

    fd = open('/dev/button',O_RDWR);

    if(fd < 0){

    perror('open');

    exit(1);

    }


    while(1){

    bzero(&event,sizeof(event));

    ret = read(fd,&event,sizeof(event));

#if 0

    if(ret < 0){

        perror('read');

        exit(1);

    }

#endif

    if(event.code == KEY_DOWN){

        if(event.value)

        printf('按下了下键!n');

        else

        printf('松开了下键!n');

    }

    sleep(1);

    }


    close(fd);

    return 0;

}


#指定内核源码路径

KERNEL_DIR = /home/farsight/s5pv210/kernel/linux-3.0.8

CUR_DIR = $(shell pwd)

MYAPP = test


all:

    #让make进入内核源码编译,同时将当前目录中的c程序作为内核模块一起编译

    make -C $(KERNEL_DIR) M=$(CUR_DIR) modules

    arm-none-linux-gnueabi-gcc -o $(MYAPP) $(MYAPP).c


clean:

    #删除上面编译生成的文件

    make -C $(KERNEL_DIR) M=$(CUR_DIR) clean

    rm -rf $(MYAPP)


install:

    cp *.ko $(MYAPP) /opt/rootfs/drv_module


#指定当前目录下哪个文件作为内核模块编

obj-m = button_drv.o

[1] [2]
关键字:非阻塞IO  s5pv210 引用地址:代码示例_非阻塞IO

上一篇:ARM Cortex-A Series Processors
下一篇:[kernel 启动流程] (第四章)第一阶段之——dtb的验证

推荐阅读最新更新时间:2026-03-20 14:05

同步与异步IO阻塞阻塞IO
很多时候我们常常看到同步与异步,阻塞与非阻塞的出现。有的地方直接将同步与阻塞画上了等号。异步与非阻塞画上了等号。事实上这是不对的。同步不等于阻塞,而异步也不等于非阻塞。下面就来仔细的看看同步与异步、阻塞与非阻塞的概念差别,及他们的组合应用。 同步:所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。按照这个定义,其实绝大多数函数都是同步调用(例如sin, isdigit等)。但是一般而言,我们在说同步、异步的时候,特指那些需要其他部件协作或者需要一定时间完成的任务。最常见的例子就是 SendMessage。该函数发送一个消息给某个窗口,在对方处理完消息之前,这个函数不返回。当对方处理完毕以后,该函数才把消息处理函
[单片机]
同步与异步<font color='red'>IO</font>、<font color='red'>阻塞</font>与<font color='red'>非</font><font color='red'>阻塞</font><font color='red'>IO</font>
S5PV210中的定时器
什么是定时器? 定时器是SoC中常见外设 定时器与计数器。计数器是用来计数的(每隔一个固定时间会计一个数),因为计数器的技术时间周期是固定的,因此到了一定时间,只要用计数值乘以技术的时间周期就能得到一个时间段。这个时间段就是我们定的时间(这就是定时器了)。 定时器/计数器作为SoC的外设,主要用来实现定时执行代码功能,定时器相对于SoC来说,就好像闹钟相对于人来说意义一样 定时器有什么用? 定时器可以让SoC在执行主程序的同时,可以(通过定时器)具有计时功能,到了一定时间(计时结束)后,定时器会产生中断提醒CPU,CPU回去处理中断并执行定时器中断的isr从而去执行预先设定好的事件。 定时器就好像是CPU的秘书一样,这
[单片机]
tslib移植(针对s5pv210,cw210开发板)
tslib移植:   tslib是为了控制触摸屏的开源程序,那么为了用于我的开发板(cortex-a8系列的cw210开发板),那么要有特定的配置才能用于指定的开发板。 1.下载tslib-1.4.tar.gz 2.解压: ##tar zxvf tslib-1.4.tar.gz 3.配置: ##cd tslib ##./autogen.sh ##./configure --prefix=$(pwd)/_install --host=arm-linux ac_cv_func_malloc_0_nonnull=yes ps:--prefix=$(pwd)/_install是指定安装目录为当前目录的_install目录 --host
[单片机]
tslib移植(针对<font color='red'>s5pv210</font>,cw210开发板)
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
【ARM裸机s5pv210 】芯片初始化
#define GPJ0CON 0xE0200240 #define GPJ0DAT 0xE0200244 #define WTCON 0xE2700000 #define SVC_STACK 0xd0037d80 .global _start _start: // 第1步:关看门狗(向WTCON的bit5写入0即可) ldr r0, =WTCON ldr r1, =0x0 str r1, // 第2步:设置SVC栈    满减栈,满的意思是入栈先移动指针再填入数据,减的意思是栈从高到低用 ldr sp, =SVC_STACK // 第3步:开/关icache
[单片机]
tiny210(s5pv210)移植u-boot(基于 2014.4 版本号)——NAND 8位硬件ECC
这节我们实现nand的ecc,保存环境变量到nand flash 中。然后把我们之前的led灯烧写到nand flash 中。开机启动。在 tiny210.h 中定义宏 CONFIG_S5PV210_NAND_HWECC、CONFIG_SYS_NAND_ECCSIZE、CONFIG_SYS_NAND_ECCBYTES CONFIG_SYS_NAND_ECCSIZE 定义了消息长度。即每多少字节进行 1 次 ECC 校验 CONFIG_SYS_NAND_ECCBYTES 定义为 13Byte,将 drivers/mtd/nand/s5pv210_nand.c 中的 CONFIG_S3C2410_NAND_HWECC 替换为CON
[单片机]
tiny210(<font color='red'>s5pv210</font>)移植u-boot(基于 2014.4 版本号)——NAND 8位硬件ECC
u-boot1.3.4向S5PV210移植
一、串口无输出   按源码编译后,串口无输出。开发板供电锁存成功。   进入start.S中查看,发现多了PMIC_InitIp,即电源管理模块初始化。屏蔽后发现串口可以输出。 二、DDR配置信息修改   从启动打印信息,以及bdinfo命令中可以看到SDRAM的设置错误。   使用md和mw命令测试内存,发现20000000和40000000开头的内存都是可以用的,说明代码中DDR初始化部分是正确的,只是size错了。   改用如下配置 #define MEMORY_BASE_ADDRESS 0x30000000 #define CONFIG_NR_DRAM_BANKS 2 /* we have 2 ban
[单片机]
Tiny210v2( S5PV210 )平台下创建基本根文件系统
0. 概要介绍 ========================================================= 根文件系统的建立,可以有多种方式。 * 直接利用开发板供应商提供的根文件系统; * 利用开源社区的发行版,比如debian/ubuntu for arm; * 利用meego/tizen/moblin/android提供的根文件系统; * 自己建立。 其中最方便的还是利用别人已经完成的成果,避免重新发明轮子。 但如果别人已有的成果不能满足自己需求,或者想要体验一下根文件系统如何建立的话,还是需要自己来实践一下。 在这里记录一下我建立最小根文件系统的过程,以防忘记。 这个方法不一定是正统方法,只是一个可
[单片机]
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

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

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

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