前言
本文将带大家学习驱动程序的具体编写及出口入口函数解析。
一、出口函数入口函数解析
每一个驱动程序都是含有出口函数和入口函数的,装载驱动的时候先调用入口函数,卸载驱动的时候则调用出口函数。
入口出口函数的形式如下:
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就只是一个空的宏,入口函数和出口函数在整个过程中都只会调用一次,调用完后我们可以将其释放节省内存,使用这两个标识就可以达到这样的效果。
二、printk内核打印信息
在普通的程序中我们一般使用的是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");
总结
本篇文章的内容不多大家看完后有什么疑问可以留言。