• 搭建字符驱动的框架


      1、驱动三要素:

    /*头文件*/
    #include <linux/init.h>
    #include <linux/module.h>
    
    /*加载函数*/
    module_init();
    /*卸载函数*/
    module_exit();

      2、驱动初始化

    1)申请设备号

    /*静态申请*/
    int register_chrdev_region(dev_t from, unsigned count, const char *name)
    指定从设备号from开始,申请count个设备号,在
    /proc/devices中的名字为name。 返回值: 成功返回0,失败返回错误码。
    /*动态申请*/ int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)
    动态申请从次设备号baseminor开始的count个设备号,在
    /proc/devices中的名字为name,并通过dev指针把分配到的设备号返回给调用函数者。 返回值: 成功返回0,失败返回错误码。

    2)字符设备的注册(告诉内核操作设备的函数)

    注册函数用结构体struct cdev来表示一个字符设备。字符设备的注册就是要定义一个这样的结构体并且填上对应的内容。

    先看一下结构体的成员,没注释的是内核自己要填的。
    /*/include/linux/cdev.h*/
    struct cdev {
        struct kobject kobj;
        struct module *owner;    //一般初始化为THIS_MODULE
        const struct file_operations *ops;    //文件操作结构体
        struct list_head list;
        dev_t dev;    //设备号
        unsigned int count;    //添加的设备个数
    };

    注册也分为三个步骤:

      1)分配cdev

      2)初始化cdev

      3)添加cdev

    分配cdev简单的说就是定义一个cdev结构体

    方法一:直接定义:
    struct cdev test_cdev;
    方法二:调用函数:struct cdev* cdev_alloc(void)
    struct cdev* test_cdev;
    test_cdev = cdev_alloc();

    初始化cdev将文件操作结构体添加到cdev中:

    void cdev_init(struct cdev *cdev, const struct file_operations *fops)
    参数:
    cdev:之前我定义的cdev结构体;
    fops:设备对应的文件操作结构体。
    返回值:(函数有可能失败,查看返回值是必须的)
    成功返回0,示范返回对应的错误码

    这个函数干了两件事情:

      1)内核自己填充了结构体中list和kobj的内容

      2)把我传入的文件操作结构体也填充进去。

    一般的,还要手工定义结构体成员owner。

    struct file_operations test_fops;
    cdev_init(&test_cdev, &test_fops);
    test_cdev->owner = THIS_OWNER    //指定模块的所属

    添加cdevcdev结构体与设备号关联起来:

    int cdev_add(struct cdev *cdev, dev_t dev, unsigned count)
    参数:
    cdev:指定要被添加的cdev结构体;
    dev:对应的设备号
    count:从设备号dev开始添加count个设备.
    返回值:
    成功返回0,失败返回对应的错误码。

    函数干了也两件事:

      1)把cdev结构体中还没填充的两个成员dev和count按照传入参数赋值。

      2)把cdev结构体中传入内核,这样内核就知道对应设备号和具体的文件操作结构体了。

      3、实现设备操作

    定义file_operation,并添加实现函数

      4、驱动注销

    /*删除cdev*/
    void
    cdev_del(struct cdev *p)
    使用:这是添加的逆操作,模块卸载时调用
    /*释放设备号*/

     void unregister_chrdev_region(dev_t from, unsigned count)

     使用:释放从from开始count个设备号。

    此外,还可以自动生成字符类设备节点:

    首先定义

    static struct class *xxx_class;

    static struct class_device *xxx_class_dev;

    1、创建设备类

    class_create

    2、释放设备类

    class_destroy

    3、创建字符类设备节点

    class_device_create

    4、摧毁设备节点

    class_device_unregister

  • 相关阅读:
    Linux 下复制命令行输出内容或直接复制文本内容
    JavaScript Array contrast
    Docker安装 Mysql 8.0 并挂载外部配置和数据
    IPC 方法分类
    Linux 安装各种常用通讯软件
    Docker--关于域名和端口配置问题总结
    Golang--Directional Channel(定向通道)
    数位dp
    STL:reverse函数、upper_bound函数、lower_bound函数
    vue filter中无法访问this的解决方案
  • 原文地址:https://www.cnblogs.com/yiyedada/p/5801719.html
Copyright © 2020-2023  润新知