• Linux驱动开发 驱动程序的具体编写及出口入口函数解析,printk打印内核信息



    前言

    本文将带大家学习驱动程序的具体编写及出口入口函数解析。

    一、出口函数入口函数解析

    每一个驱动程序都是含有出口函数和入口函数的,装载驱动的时候先调用入口函数,卸载驱动的时候则调用出口函数。
    入口出口函数的形式如下:

    static __init int hello_dev_init(void)
    {
    	printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);	
    	return 0;
    }
    
    static __exit void hello_dev_exit(void)
    {
    	printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
    }
    
    
    module_init(hello_dev_init);
    module_exit(hello_dev_exit);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    module_init和module_exit的作业是将上面两个函数分别修饰为入口函数和出口函数,一般的函数我们不能随意指定他就是出口函数和入口函数,必须经过指定后才能认为他是入口函数和出口函数。

    有同学可能会有疑惑为什么这两个函数前面要加__init和__exit呢?
    其实__init和__exit就只是一个空的宏,入口函数和出口函数在整个过程中都只会调用一次,调用完后我们可以将其释放节省内存,使用这两个标识就可以达到这样的效果。
    在这里插入图片描述

    二、printk内核打印信息

    在普通的程序中我们一般使用的是printf来输出打印信息,但是在Linux内核中要用printk来打印输出信息。
    一般默认情况下内核的打印信息是没有打开的,我们需要将其打开。

    cat /proc/sys/kernel/printk//查看设置值
    echo 7       4       1      7 > /proc/sys/kernel/printk//打开内核打印信息
    
    • 1
    • 2

    将内核的打印功能打开后我们就可以使用printk去打印输出信息了。

    三、驱动程序的具体编写

    1.确定主设备号
    主设备号可以由我们自己指定,也可以由系统帮我们指定。

    static int major = 0;
    
    • 1

    2.构造file_operations结构体

    static struct file_operations hello_drv = {
    	.owner	 = THIS_MODULE,
    	.open    = hello_drv_open,
    	.read    = hello_drv_read,
    	.write   = hello_drv_write,
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.实现对应的open,read,write函数

    static ssize_t hello_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
    {
    	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    	return 1;
    }
    
    static ssize_t hello_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
    {
    	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    	return 1;
    }
    
    static int hello_drv_open (struct inode *node, struct file *file)
    {
    	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    4.注册驱动程序
    在Linux中我们会经常听到注册这个词,注册其实就是将结构体添加进链表。

    major = register_chrdev(0, "hello", &hello_drv);
    
    • 1

    5.编写入口函数

    static int __init hello_init(void)
    {
    	int err;
    	
    	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    	major = register_chrdev(0, "hello", &hello_drv);  /* /dev/hello */
    
    
    	hello_class = class_create(THIS_MODULE, "hello_class");
    	err = PTR_ERR(hello_class);
    	if (IS_ERR(hello_class)) {
    		printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    		unregister_chrdev(major, "hello");
    		return -1;
    	}
    	
    	device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello"); /* /dev/hello */
    	
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    6.编写出口函数

    static void __exit hello_exit(void)
    {
    	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    	device_destroy(hello_class, MKDEV(major, 0));
    	class_destroy(hello_class);
    	unregister_chrdev(major, "hello");
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    7.完善信息

    module_init(hello_init);
    module_exit(hello_exit);
    
    MODULE_LICENSE("GPL");
    
    • 1
    • 2
    • 3
    • 4

    总结

    本篇文章的内容不多大家看完后有什么疑问可以留言。

  • 相关阅读:
    此芯科技加入百度飞桨硬件生态共创计划,加速端侧AI生态布局
    基于SSM的文物管理系统
    C++虚函数的vptr与vtable
    【Linux多线程服务端编程】| 【05】高效的多线程日志
    python数据分析与展示--Matplotlib库入门
    1113: 递归调用的次数统计(函数专题)
    【C++】基础知识点回顾 下:auto关键字、范围内的for循环
    户外暴晒测试系统太阳光模拟器
    蓝桥杯-子 2023 / 双子数
    SpringCloud之注册中心
  • 原文地址:https://blog.csdn.net/m0_49476241/article/details/125524771