• 注册字符设备驱动


    1. 模块加载
    #include 
    #include 
     
    /* 驱动入口函数 */
    static int __init xxx_init(void)
    {
        /* 入口函数具体内容 */
     
        return 0;
    }
     
    /* 驱动出口函数 */
    static void __exit xxx_exit(void)
    {
        /* 出口函数具体内容 */
    }
    
    /* 将上面两个函数指定为驱动的入口和出口函数 */
    module_init(xxx_init);
    module_exit(xxx_exit)
    MODULE_LICENSE("GPL");//GPL模块许可证
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    1. 注册字符设备驱动
      对于字符设备驱动而言,当驱动模块加载成功以后需要注册字符设备。卸载驱动模块的时也需要注销掉字符设备。

    字符设备的注册和注销函数原型:

    static inline int register_chrdev(unsigned int major, const char *name,
    const struct file_operations *fops)
     
    static inline void unregister_chrdev(unsigned int major, const char *name)
    
    • 1
    • 2
    • 3
    • 4

    register_chrdev 函数用于注册字符设备,需要传入主设备号,设备名称和指向设备操作函数集合变量。这种注册函数会将后面所有的次设备号全部占用,而且主设备号需要我们自己去设置,现在不推荐这样使用。一般字符设备的注册在驱动模块的入口函数 xxx_init 中进行,字符设备的注销在驱动模块的出口函数 xxx_exit 中进行。

    static int led_open(struct inode *inode, struct file *filp)
    {
    	return 0;
    }
     
    /*
     * @description		: 从设备读取数据 
     * @param - filp 	: 要打开的设备文件(文件描述符)
     * @param - buf 	: 返回给用户空间的数据缓冲区
     * @param - cnt 	: 要读取的数据长度
     * @param - offt 	: 相对于文件首地址的偏移
     * @return 			: 读取的字节数,如果为负值,表示读取失败
     */
    static ssize_t led_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
    {
    	return 0;
    }
     
    /*
     * @description		: 向设备写数据 
     * @param - filp 	: 设备文件,表示打开的文件描述符
     * @param - buf 	: 要写给设备写入的数据
     * @param - cnt 	: 要写入的数据长度
     * @param - offt 	: 相对于文件首地址的偏移
     * @return 			: 写入的字节数,如果为负值,表示写入失败
     */
    static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
    {
    	return 0;
    }
     
    /*
     * @description		: 关闭/释放设备
     * @param - filp 	: 要关闭的设备文件(文件描述符)
     * @return 			: 0 成功;其他 失败
     */
    static int led_release(struct inode *inode, struct file *filp)
    {
    	return 0;
    }
     
    //设备操作函数 
    static struct file_operations led_fops = {
    	.owner = THIS_MODULE,
    	.open = led_open,
    	.read = led_read,
    	.write = led_write,
    	.release = 	led_release,
    };
     
    //驱动入口函数
    static int __init led_init(void)
    {
    	int retvalue = 0;
     
    	/*注册字符设备驱动 */
    	retvalue = register_chrdev(LED_MAJOR, LED_NAME, &led_fops);
    	if(retvalue < 0){
    		printk("register chrdev failed!\r\n");
    		return -EIO;
    	}
    	return 0;
    }
    //驱动出口函数
    static void __exit led_exit(void)
    {
    	/* 注销字符设备驱动 */
    	unregister_chrdev(LED_MAJOR, LED_NAME);
    }
    
    module_init(led_init);
    module_exit(led_exit);
    MODULE_LICENSE("GPL");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
  • 相关阅读:
    前端教程-TypeScript
    Vue3 父组件调用子组件方法($refs 在setup()、<script setup> 中使用)
    (附源码)springboot新闻管理系统 毕业设计 211113
    10.22 校招 实习 内推 面经
    分享两个实用的PPT制作技巧
    全局后置路由守卫(afterEach)
    [暑假-边做边学版]Vue实战(2)
    FlinkCDC介绍及使用
    【ESP-IDF环境搭建,下载编译第一个程序】
    详解设计模式:适配器模式
  • 原文地址:https://blog.csdn.net/qqmrchen124/article/details/134466413