zoukankan      html  css  js  c++  java
  • 第一个驱动之字符设备驱动(二)mdev

    mdev是busybox提供的一个工具,用在嵌入式系统中,相当于简化版的udev,作用是在系统启动和热插拔或动态加载驱动程序时, 自动创建设备节点。文件系统中的/dev目录下的设备节点都是由mdev创建的。在加载驱动过程中,根据驱动程序,在/dev下自动创建设备节点。

    前面的博客实现了第一个版本,但是需要手工创建字符设备节点,这里使用mdev自动创建。

    源代码如下:

    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/fs.h>
    #include <linux/init.h>
    #include <linux/delay.h>
    #include <asm/uaccess.h>
    #include <asm/irq.h>
    #include <asm/io.h>
    #include <asm/arch/regs-gpio.h>
    #include <asm/hardware.h>
    
    static struct class *first_drv_class;
    static struct class_device    *first_drv_class_devs;
    int auto_major;
    static int first_drv_open(struct inode *inode, struct file *file)
    {
        printk("first_drv_open...
    ");
        return 0;
    }
    
    static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
    {
        printk("first_drv_write...
    ");
        return 0;
    }
    
    /* 这个结构是字符设备驱动程序的核心
     * 当应用程序操作设备文件时所调用的open、read、write等函数,
     * 最终会调用这个结构中指定的对应函数
     */
    static struct file_operations first_drv_fops = {
        .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
        .open   =   first_drv_open,            
        .write    =    first_drv_write,       
    };
    int fisrt_drv_init(void)
    {
        auto_major=register_chrdev(0, "first_drv", &first_drv_fops);
        
        first_drv_class = class_create(THIS_MODULE, "firstdrv");
        first_drv_class_devs = class_device_create(first_drv_class, NULL, MKDEV(auto_major, 0), NULL, "xyz"); /* /dev/xyz */
    
        return 0;
    }
    
    void fisrt_drv_exit(void)
    {
        unregister_chrdev(auto_major, "first_drv");
        
        class_device_unregister(first_drv_class_devs);
        class_destroy(first_drv_class);
    }
    
    module_init(fisrt_drv_init);
    module_exit(fisrt_drv_exit);
    
    MODULE_AUTHOR("http://www.100ask.net");
    MODULE_VERSION("0.1.0");
    MODULE_DESCRIPTION("S3C2410/S3C2440 LED Driver");
    MODULE_LICENSE("GPL");

    查看现在的字符设备,没有发现有first_drv节点:

    加载.ko文件之后出现first_drv设备:

    此时查看自动创建的/dev/xyz文件:

    然后卸载挂载的驱动first_drv之后,发现/dev/xyz文件自动消失,而且first_drv设备也自动消失了:

    这样,就避免了每次都手动创建设备节点了。

    Summary:

    现在关于内核驱动的函数,我们先学会怎么去使用,跟着韦老师的步伐,之后会有专门的内核源码和驱动的分析,那是入门之后的事情,现在先知道怎么调用API,后面进阶的时候需要阅读源码。毕竟先学会使用,第一可以让自己兴趣更大,一来就阅读源码会很吃力,第二可以快速先入门,第三,可以自己做点小东西。学习是循序渐进的一个过程。

    一个字符设备或块设备都有一个主设备号和一个次设备号。主设备号用来标识与设备文件相连的驱动程序,用来反映设备类型。次设备号被驱动程序用来辨别操作的是哪个设备,用来区分同类型的设备。

    字符驱动中提及到了次设备号,它可以被用来区分不同的操作:

    创建不同的次设备号,我们可以根据次设备号执行不同的操作,比如:

        printf("Usage:
    ");
        printf("%s <dev> <on|off>
    ",file);
        printf("eg. 
    ");
        printf("%s /dev/leds on
    ", file);
        printf("%s /dev/leds off
    ", file);
        printf("%s /dev/led1 on
    ", file);
        printf("%s /dev/led1 off
    ", file);

    ./ledtest  /dev/leds on:表示全部led亮

    ./ledtest  /dev/led1 on:表示第一个led亮

    这样的效果可以通过次设备不同来实现。内核中有获取次设备号的函数,在open和write时有不同的操作,还是那句话,具体的内核函数实现,我们之后再说,先在先会使用API就行。

  • 相关阅读:
    C# 填充客户端提交的值到T对象
    mvc中hangfire全局简单配置
    mvc企业微信开发全局配置
    js获取简单表单对象(1)
    MVC伪静态路由简单搭配
    [转]一些实用的图表Chart制作工具
    【转】SQL Server 数据库内部版本号
    SVN的搭建和使用总结
    解决ext时间插件在谷歌下变宽的BUG
    Hibernate中Session.get()/load()之区别
  • 原文地址:https://www.cnblogs.com/yangguang-it/p/8698844.html
Copyright © 2011-2022 走看看