首页 > 系统相关 >《Linux设备驱动程序》(第三版) 第1章 设备驱动程序简介

《Linux设备驱动程序》(第三版) 第1章 设备驱动程序简介

时间:2025-01-09 10:34:10浏览次数:3  
标签:驱动程序 simple 代码 module 内核 模块 Linux 设备

1.1 什么是设备驱动程序

1.1.1 驱动程序的角色

驱动程序充当硬件设备与操作系统内核之间的桥梁。它使得内核能够与特定硬件进行交互,负责将内核的抽象指令转换为硬件可理解的操作,同时将硬件的状态和数据反馈给内核。

1.1.2 字符设备、块设备和网络设备
  • 字符设备:以字符为单位顺序处理数据的设备,如串口、键盘等。字符设备驱动程序通常实现 readwrite 等方法,以字节流的形式处理数据。
  • 块设备:以数据块为单位进行数据传输的设备,如硬盘、闪存等。块设备通常支持随机访问,数据的读写以块(通常为512字节或其倍数)为单位。
  • 网络设备:用于网络通信的设备,如以太网卡。网络设备驱动主要处理网络数据包的发送和接收,与字符设备和块设备的接口方式有所不同。

1.2 为什么要写驱动程序

1.2.1 为新硬件写驱动程序

当出现新的硬件设备时,操作系统内核原生可能不支持该设备,需要编写驱动程序,使内核能够识别并控制该硬件,发挥其功能。

1.2.2 访问内核服务

驱动程序处于内核空间,可以访问内核提供的各种服务和资源,如内存管理、进程调度等,以实现更高效的设备控制和数据处理。

1.2.3 与内核开发者交流

参与驱动程序开发有助于与内核开发者社区互动,分享经验、获取反馈,共同推动内核及驱动生态的发展。

1.3 设备驱动程序的模块形式

1.3.1 什么是内核模块

内核模块是一种可动态加载和卸载的内核代码,它允许在不重新编译内核的情况下,向内核添加功能,如设备驱动、文件系统等。以下是一个简单的内核模块示例代码:

#include <linux/init.h>
#include <linux/module.h>

// 模块加载函数
static int __init simple_module_init(void) {
    // 这里开始模块初始化工作
    printk(KERN_INFO "Simple module loaded.\n");
    return 0;
}

// 模块卸载函数
static void __exit simple_module_exit(void) {
    // 这里进行模块卸载前的清理工作
    printk(KERN_INFO "Simple module unloaded.\n");
}

// 模块入口和出口声明
module_init(simple_module_init);
module_exit(simple_module_exit);

// 模块许可证声明
MODULE_LICENSE("GPL");

在上述代码中:

  • #include <linux/init.h>#include <linux/module.h> 引入了编写内核模块所需的头文件。
  • static int __init simple_module_init(void) 定义了模块的加载函数。__init 标记此函数仅在模块初始化时使用,减少内核内存占用。函数内部使用 printk 打印一条信息,表示模块已加载。printk 是内核空间的打印函数,KERN_INFO 是日志级别,表明这是一条普通信息。
  • static void __exit simple_module_exit(void) 定义了模块的卸载函数。__exit 标记此函数仅在模块卸载时使用。函数内部同样使用 printk 打印信息,表示模块已卸载。
  • module_init(simple_module_init)module_exit(simple_module_exit) 声明了模块的入口和出口函数,告诉内核在加载和卸载模块时分别调用哪个函数。
  • MODULE_LICENSE("GPL") 声明了模块的许可证为GPL,这是内核模块常见的许可证要求。
1.3.2 模块的优点
  • 动态加载与卸载:无需重启系统或重新编译内核,即可根据需要加载或卸载模块,方便设备的管理和调试。
  • 减少内核体积:将不常用的功能以模块形式存在,避免内核镜像过于庞大,提高内核的启动速度和资源利用率。
  • 便于开发和维护:不同的模块可以独立开发、调试和维护,降低开发难度,提高代码的可维护性。

1.4 为什么要关心内核版本

1.4.1 内核版本号

Linux内核版本号由三部分组成,如 x.y.zx 为主版本号,y 为次版本号(偶数表示稳定版本,奇数表示开发版本),z 为修订号,每次内核代码修改都会增加修订号。

1.4.2 内核版本的差异

不同内核版本在API、功能特性、驱动支持等方面可能存在差异。新的内核版本可能引入新的设备驱动接口、优化性能或修复安全漏洞。编写驱动程序时,需要确保代码与目标内核版本兼容,否则可能导致驱动无法正常工作。

1.5 本书的示例代码

1.5.1 获得示例代码

通常可以从本书的官方网站、相关代码托管平台(如GitHub)或随书附带的资源中获取示例代码。

1.5.2 安装示例代码

获取代码后,根据具体的代码结构和目标系统,可能需要将代码解压到合适的目录,如 /usr/src/ 下的自定义目录中,以便后续编译和使用。

1.5.3 编译示例代码

假设示例代码是一个简单的内核模块,编写如下 Makefile

# KERNELDIR指向内核源码目录,需根据实际情况修改
KERNELDIR := /lib/modules/$(shell uname -r)/build
# 当前目录
PWD := $(shell pwd)

# 目标
obj - m := simple_module.o

# 编译规则
all:
    $(MAKE) - C $(KERNELDIR) M=$(PWD) modules

# 清理规则
clean:
    $(MAKE) - C $(KERNELDIR) M=$(PWD) clean

在上述 Makefile 中:

  • KERNELDIR := /lib/modules/$(shell uname -r)/build 定义了内核源码目录,$(shell uname -r) 获取当前系统的内核版本号。
  • PWD := $(shell pwd) 获取当前工作目录。
  • obj - m := simple_module.o 表示要编译的模块为 simple_module.o
  • all 目标用于编译模块,$(MAKE) - C $(KERNELDIR) M=$(PWD) modules 命令进入内核源码目录并在当前目录下编译模块。
  • clean 目标用于清理编译生成的文件,$(MAKE) - C $(KERNELDIR) M=$(PWD) clean 命令进入内核源码目录并在当前目录下执行清理操作。

编译时,在示例代码目录下执行 make 命令即可。

1.5.4 示例代码的使用说明

编译成功后,会生成对应的 .ko 文件(如 simple_module.ko)。使用 sudo insmod simple_module.ko 命令加载模块,使用 sudo rmmod simple_module 命令卸载模块。同时,可以通过查看内核日志(如 dmesg 命令)来查看模块加载和卸载过程中的打印信息,以了解模块的运行情况。

标签:驱动程序,simple,代码,module,内核,模块,Linux,设备
From: https://blog.csdn.net/qq_40844444/article/details/145002075

相关文章

  • 《Linux设备驱动程序》(第三版)的详细目录
    以下是《Linux设备驱动程序》(第三版)的详细目录:前言本书的目标本书的组织结构本书的约定排版约定代码约定本书使用的内核版本获得帮助反馈第1章设备驱动程序简介1.1什么是设备驱动程序1.1.1驱动程序的角色1.1.2字符设备、块设备和网络设备1.2为什么要写驱动程......
  • 《Linux设备驱动程序》(第三版)第3章 字符设备驱动程序(续)
    3.1并发和竞争条件3.1.1竞争条件的概念竞争条件是指当多个执行单元(如进程、线程或中断处理程序)同时访问和修改共享资源时,由于执行顺序的不确定性而导致的不可预测的结果。例如,两个进程同时读取一个共享变量,然后各自对其进行修改并写回,最终的结果可能取决于哪个进程最后......
  • 清理linux的buff/cache缓存
    前言:在Linux系统中,buff/cache通常指的是缓冲区和缓存。这两个概念是内核管理的,用于加速对磁盘和文件的访问。清理这部分内存通常是为了释放内存空间供其他用途使用,但这并不是一个常见的操作,因为内核会自动管理这部分内存。如果你确实需要清理buff/cache,可以通过执行sync命令来确......
  • 思科网络设备常用巡检命令(建议收藏)
    在网络运维工作中,定期巡检设备是确保网络稳定运行的重要动作,思科设备作为网络架构中的重要组成部分,掌握相应巡检命令对于运维人员来说至关重要。下面将详细介绍常规的一些思科网络设备巡检命令。目 录1、思科路由交换2、思科ASA防火墙3、思科Nexus交换机1、思科路由......
  • 学习 - Linux - CentOS安装Tomcat8.5.85
    CentOS安装Tomcat8.5.851、保证已经安装了jdk运行环境java-version如果没有,请参考Centos安装jdk2、从Apache官方网站下载Tomcat8cd/optsudowgethttps://archive.apache.org/dist/tomcat/tomcat-8/v8.5.85/bin/apache-tomcat-8.5.85.tar.gz3、载完成后,解压缩Tomca......
  • Linux通过端口找到对应的服务
      首先执行netstat-tulnp|grep<端口号>例如:netstat-tulnp|grep:80参数解释:-t:显示 TCP 连接(只显示TCP协议的端口信息)。-u:显示 UDP 连接(只显示UDP协议的端口信息)。-l:显示正在监听(Listening)状态的端口(只显示处于监听状态的端口)。-n:以数字格式显......
  • linux上安装jdk
    linux上安装jdk注意:以下所有命令在centos7.6环境下测试,其他linux环境请自行测试注意:在linux中,不是管理员登录,最好在指令前加上sudo提权,避免权限不够执行失败带来的麻烦,以下命令请都加上sudo,这是一个好习惯。安装linux时预装jdk,选择软件时勾上开发组件卸载jdkjava-version ......
  • Java Bluetooth 蓝牙通讯 BlueCove 扫描附近的蓝牙设备
    目录BlueCove项目概述BlueCoveAPI架构API的设计原则和实现方式关键类和方法的功能描述测试代码获取本机(PC)蓝牙扫描蓝牙BlueCove项目概述BlueCove是一个开源的蓝牙协议栈实现,旨在为Java开发者提供一个全面的、易于使用的API,从而在应用程序中实现蓝牙功能。该项目支持多种操作......
  • [Linux]线程概念与控制
    目录一、线程概念1.什么是线程2.线程的轻量化3.LWP字段4.局部性原理5.线程的优缺点6.进程VS线程二、线程的控制1.线程创建2.获取线程id3.线程退出与等待4.创建轻量级进程三、线程的管理1.pthread库管理线程2.线程局部存储四、C++线程库1.构造函数 2.成员函......
  • Linux 下>> << > <介绍
    在Linux或类Unix系统的命令行中,>>、<<、>和<是用于重定向输入输出的操作符。它们允许你控制命令的输入和输出,改变数据流的方向。这些符号是常见的I/O重定向符号,在shell脚本和命令行操作中非常有用。(输出重定向,覆盖文件)用于将命令的标准输出(stdout)重定向到......