• 代码示例_非阻塞IO



    //头文件
    #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 <asm/io.h>
    #include <asm/string.h>
    #include <asm/uaccess.h>
    #include <asm-generic/ioctl.h>
    
    #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------------
    ",__FUNCTION__);
        //获取按键信息
        value = gpio_get_value(S5PV210_GPH0(1));
        //判断是按下还是松开
        if(value){
            //松开
            printk("kenel:keydown up!
    ");
            button_dev->event.code = KEY_DOWN;
            button_dev->event.value = 0;
        }else{
            //按下
            printk("kenel:keydown pressed!
    ");
            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------------
    ",__FUNCTION__);
        
        return 0;
    }
    ssize_t button_read(struct file *filp , char __user *buf , size_t size, loff_t *flags)
    {
        int ret;
        printk("--------^_^ %s------------
    ",__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!
    ");
            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------------
    ",__FUNCTION__);
    
        return size;
    }
    
    long button_ioctl(struct file *filp, unsigned int cmd , unsigned long args)
    {
        
        printk("--------^_^ %s------------
    ",__FUNCTION__);
        
        return 0;
    }
    
    int button_close(struct inode *inode, struct file *filp)
    {
        printk("--------^_^ %s------------
    ",__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------------
    ",__FUNCTION__);
        //0,实例化设备对象
        //参数1 ---- 要申请的空间的大小
        //参数2 ---- 申请的空间的标识
        button_dev = kzalloc(sizeof(struct s5pv210_button),GFP_KERNEL);
        if(IS_ERR(button_dev)){
            printk("kzalloc error!
    ");
            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!
    ");
            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!
    ");
            ret =  -EINVAL;
            goto err_kfree;
        }
    #endif
    
        //创建cdev
    
        //申请cdev的空间
        button_dev->cdev = cdev_alloc();
        if(IS_ERR(button_dev->cdev)){        
            printk("button_dev->cdev error!
    ");
            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!
    ");
            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!
    ");
            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!
    ");
            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------------
    ",__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 <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <sys/ioctl.h>
    #include <linux/input.h>
    
    //定义一个按键的数据包
    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("按下了下键!
    ");
            else
            printf("松开了下键!
    ");
        }
        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
    Stay hungry, stay foolish 待续。。。
  • 相关阅读:
    $dp$模板
    字符串基础
    基础算法

    图论
    山中无甲子,寒尽不知年
    模板集合(持续更新)
    数学基础——同余
    9.19 考试总结
    1-5-17:菲波那契数列
  • 原文地址:https://www.cnblogs.com/panda-w/p/10991411.html
Copyright © 2020-2023  润新知