• linux驱动开发(四) 字符设备驱动框架(自动创建设备节点)


    代码如下

    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/cdev.h>
    #include <linux/fs.h>
    #include <linux/device.h>  
    
    
    int demo_major = 250;
    int demo_minor = 0;
    int demo_count = 1;
    
    struct cdev cdev;
    
    static struct class *demo_class;
    static struct device *demo_device;
    
    int  demo_open(struct inode *inodep, struct file * filep) // 打开设备
    {
        printk("%s,%d
    ", __func__, __LINE__);
        return 0;
    }
    
    int demo_release(struct inode * inodep, struct file * filep)  // 关闭设备
    {
        printk("%s,%d
    ", __func__, __LINE__);
        return 0;
    }
    
    struct file_operations  fops =
    {
        .owner = THIS_MODULE,
        .open = demo_open,
        .release = demo_release,
    };
    
    static int __init demo_init(void)
    {
        int ret = 0;
        dev_t  devno;
        
        printk("%s,%d
    ", __func__, __LINE__);
    
        //使用下列宏则可以通过主设备号和次设备号生成 dev_t
        devno = MKDEV(demo_major, demo_minor);
    
        printk("devno:%d
    ", devno);
        printk("demo_major:%d
    ", demo_major);
    
        /**在调用 cdev_add()函数向系统注册字符设备之前,
          *应首先调用 register_chrdev_region()或alloc_chrdev_region()函数向系统申请设备号
          **/
        if (demo_major)
        {
         //使用cat /proc/devices | grep demo 来查询 ret
    = register_chrdev_region(devno, 1, "demo"); } else { ret = alloc_chrdev_region(&devno, demo_minor, 1, "demo"); } if(ret) { printk("Failed to register_chrdev_region. "); return ret; } //cdev_init()函数用于初始化 cdev 的成员,并建立 cdev 和 file_operations 之间的连接 cdev_init(&cdev, &fops); cdev.owner = THIS_MODULE; //系统添加一个 cdev,完成字符设备的注册。 ret = cdev_add(&cdev, devno, demo_count); if(ret) { printk(KERN_NOTICE " Failed to cdev_add [Error] %d adding demo%d", ret, demo_minor); goto failure_cdev_add; } /*自动创建设备节点文件*/ //1.注册设备类 /sys/class/demo的文件夹
      //使用 ls /sys/class/demo
    demo_class = class_create(THIS_MODULE, "demo"); if( IS_ERR(demo_class)) { printk("class_create failed! "); ret = PTR_ERR("demo_class"); goto failure_class_create; } //2.注册设备 /sys/class/demo/demo0 /dev/demo0 demo_device = device_create(demo_class, NULL, MKDEV(demo_major, demo_minor), NULL, "demo%d", demo_minor); if(IS_ERR(demo_device)){ printk("device_create failed! "); ret = PTR_ERR("demo_device"); goto failure_device_create; } return 0; failure_device_create: class_destroy(demo_class); failure_class_create: cdev_del(&cdev); failure_cdev_add: unregister_chrdev_region(devno, demo_count); failure_register_chrdev: return ret; } static void __exit demo_exit(void) { printk("%s,%d ", __func__, __LINE__); /*逆序消除*/ //从内核中删除设备 device_destroy(demo_class,MKDEV(demo_major, demo_minor)); //从内核中删除设备类 class_destroy(demo_class); //删除一个 cdev,完成字符设备的注销。 cdev_del(&cdev); //在调用cdev_del()函数从系统注销字符设备之后,unregister_chrdev_region()应该被调用以释放原先申请的设备号 unregister_chrdev_region( MKDEV(demo_major, demo_minor), demo_count ); } module_init(demo_init); module_exit(demo_exit); MODULE_AUTHOR(" libra13179 "); MODULE_LICENSE("GPL v2");
    KVERS = $(shell uname -r)
    
    # Kernel modules
    obj-m += demo.o
    
    # Specify flags for the module compilation.
    #EXTRA_CFLAGS=-g -O0
    
    build: kernel_modules
    
    kernel_modules:
        make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modules
    #    @echo $(KVERS)
    
    clean:
        make -C /lib/modules/$(KVERS)/build M=$(CURDIR) clean
    View Code
    #include <sys/types.h>
    
    #include <sys/stat.h>
    
    #include <fcntl.h>
    
    #include <stdio.h>
    
    
    
    
    
    int main(int argc, const char *argv[])
    
    {
    
        int fd;
    
        int val = 1;
    
        fd = open("/dev/demo0", O_RDWR);
    
        if (fd < 0)
    
        {
    
            printf("can't open!
    ");
    
            return -1;
    
        }
    
        else
    
        {
    
            printf("open success.
    ");
    
        }
    
     
    
     
    
        getchar();
    
     
    
     
    
        close(fd);
    
    
    
        return 0;
    
    }
    View Code

     

    主要使用到函数

    class_create
    device_create
    device_destroy

    class_destroy


    小技巧:
    类似
    http://lxr.free-electrons.com/
    http://lxr.oss.org.cn/
    这样的网站提供了Linux内核源代码的交叉索引,
    在其中输入Linux内核中的函数、数据结构或变量的名称就可以直接得到以超链接形式给出的定义和引用它的所有位置。
    还有一些网站也提供了Linux内核中函数、变量和数据结构的搜索功能,
    在google中搜索“linux identifier search”可得。
     
  • 相关阅读:
    面试题 面试技巧
    面试 11-02.ES6
    面试 11-00.JavaScript高级面试
    面试 11-01.ES6:模块化的使用和编译环境
    面试 10-01.页面性能优化
    面试 09-02.js运行机制:异步和单线程
    面试 10-02.前端错误监控
    选择屏幕-SELECTION-SCREEN(二)
    ◆◆0如何创建代码模板
    行选择交互事件
  • 原文地址:https://www.cnblogs.com/libra13179/p/9370045.html
Copyright © 2020-2023  润新知