本文将带大家学习驱动程序的具体编写及出口入口函数解析。
每一个驱动程序都是含有出口函数和入口函数的,装载驱动的时候先调用入口函数,卸载驱动的时候则调用出口函数。
入口出口函数的形式如下:
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);
module_init和module_exit的作业是将上面两个函数分别修饰为入口函数和出口函数,一般的函数我们不能随意指定他就是出口函数和入口函数,必须经过指定后才能认为他是入口函数和出口函数。
有同学可能会有疑惑为什么这两个函数前面要加__init和__exit呢?
其实__init和__exit就只是一个空的宏,入口函数和出口函数在整个过程中都只会调用一次,调用完后我们可以将其释放节省内存,使用这两个标识就可以达到这样的效果。
在普通的程序中我们一般使用的是printf来输出打印信息,但是在Linux内核中要用printk来打印输出信息。
一般默认情况下内核的打印信息是没有打开的,我们需要将其打开。
cat /proc/sys/kernel/printk//查看设置值
echo 7 4 1 7 > /proc/sys/kernel/printk//打开内核打印信息
将内核的打印功能打开后我们就可以使用printk去打印输出信息了。
1.确定主设备号
主设备号可以由我们自己指定,也可以由系统帮我们指定。
static int major = 0;
2.构造file_operations结构体
static struct file_operations hello_drv = {
.owner = THIS_MODULE,
.open = hello_drv_open,
.read = hello_drv_read,
.write = hello_drv_write,
};
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;
}
4.注册驱动程序
在Linux中我们会经常听到注册这个词,注册其实就是将结构体添加进链表。
major = register_chrdev(0, "hello", &hello_drv);
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;
}
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");
}
7.完善信息
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
本篇文章的内容不多大家看完后有什么疑问可以留言。