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

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 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);

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


有同学可能会有疑惑为什么这两个函数前面要加__init和__exit呢?

其实__init和__exit就只是一个空的宏,入口函数和出口函数在整个过程中都只会调用一次,调用完后我们可以将其释放节省内存,使用这两个标识就可以达到这样的效果。

1f27c2a24fae43489fc5acc40ffff145.png

二、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");

总结

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

相关文章
|
6天前
|
安全 Linux 编译器
探索Linux内核的奥秘:从零构建操作系统####
本文旨在通过深入浅出的方式,带领读者踏上一段从零开始构建简化版Linux操作系统的旅程。我们将避开复杂的技术细节,以通俗易懂的语言,逐步揭开Linux内核的神秘面纱,探讨其工作原理、核心组件及如何通过实践加深理解。这既是一次对操作系统原理的深刻洞察,也是一场激发创新思维与实践能力的冒险。 ####
|
8天前
|
网络协议 Linux 调度
深入探索Linux操作系统的心脏:内核与系统调用####
本文旨在揭开Linux操作系统中最为核心的部分——内核与系统调用的神秘面纱,通过生动形象的语言和比喻,让读者仿佛踏上了一段奇妙的旅程,从宏观到微观,逐步深入了解这两个关键组件如何协同工作,支撑起整个操作系统的运行。不同于传统的技术解析,本文将以故事化的方式,带领读者领略Linux内核的精妙设计与系统调用的魅力所在,即便是对技术细节不甚了解的读者也能轻松享受这次知识之旅。 ####
|
5天前
|
缓存 算法 安全
深入理解Linux操作系统的心脏:内核与系统调用####
【10月更文挑战第20天】 本文将带你探索Linux操作系统的核心——其强大的内核和高效的系统调用机制。通过深入浅出的解释,我们将揭示这些技术是如何协同工作以支撑起整个系统的运行,同时也会触及一些常见的误解和背后的哲学思想。无论你是开发者、系统管理员还是普通用户,了解这些基础知识都将有助于你更好地利用Linux的强大功能。 ####
13 1
|
6天前
|
缓存 编解码 监控
深入探索Linux内核调度机制的奥秘###
【10月更文挑战第19天】 本文旨在以通俗易懂的语言,深入浅出地剖析Linux操作系统内核中的进程调度机制,揭示其背后的设计哲学与实现策略。我们将从基础概念入手,逐步揭开Linux调度策略的神秘面纱,探讨其如何高效、公平地管理系统资源,以及这些机制对系统性能和用户体验的影响。通过本文,您将获得关于Linux调度机制的全新视角,理解其在日常计算中扮演的关键角色。 ###
25 1
|
12天前
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
49 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
13天前
|
网络协议 Linux 芯片
Linux 内核 6.11 RC6 发布!
【10月更文挑战第12天】
76 0
Linux 内核 6.11 RC6 发布!
|
2月前
|
存储 前端开发 JavaScript
前端基础(十二)_函数高级、全局变量和局部变量、 预解析(变量提升)、函数返回值
本文介绍了JavaScript中作用域的概念,包括全局变量和局部变量的区别,预解析机制(变量提升),以及函数返回值的使用和类型。通过具体示例讲解了变量的作用域、函数的返回值、以及如何通过return关键字从函数中返回数据。
21 1
前端基础(十二)_函数高级、全局变量和局部变量、 预解析(变量提升)、函数返回值
|
21天前
|
存储
atoi函数解析以及自定义类型经典练习题
atoi函数解析以及自定义类型经典练习题
20 0
|
25天前
|
数据处理 Python
深入探索:Python中的并发编程新纪元——协程与异步函数解析
深入探索:Python中的并发编程新纪元——协程与异步函数解析
21 3
|
25天前
|
机器学习/深度学习 算法 C语言
【Python】Math--数学函数(详细附解析~)
【Python】Math--数学函数(详细附解析~)