当前位置: 首页 > article >正文

Linux内核中的设备驱动详解

Linux内核中的设备驱动详解引言设备驱动是Linux内核中的重要组成部分它负责管理硬件设备与内核之间的通信。设备驱动为应用程序提供了访问硬件设备的接口使得应用程序可以无需了解硬件的具体实现细节。本文将深入探讨Linux内核中的设备驱动机制包括其原理、实现和应用。设备驱动的基本概念1. 设备驱动的定义设备驱动是一种软件它负责管理硬件设备与操作系统之间的通信。2. 设备驱动的类型字符设备按字节流访问的设备如串口、终端等块设备按块访问的设备如硬盘、U盘等网络设备网络通信设备如网卡等杂项设备无法归类的设备3. 设备驱动的架构应用层 ↓ 系统调用层 ↓ 设备驱动层 ↓ 硬件层设备驱动的实现1. 字符设备驱动#include linux/cdev.h #include linux/fs.h static dev_t dev_num; static struct cdev my_cdev; // 打开设备 static int my_open(struct inode *inode, struct file *file) { // 实现打开操作 return 0; } // 读取设备 static ssize_t my_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { // 实现读取操作 return count; } // 写入设备 static ssize_t my_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) { // 实现写入操作 return count; } // 释放设备 static int my_release(struct inode *inode, struct file *file) { // 实现释放操作 return 0; } // 文件操作结构 static struct file_operations my_fops { .owner THIS_MODULE, .open my_open, .read my_read, .write my_write, .release my_release, }; // 模块初始化 static int __init my_init(void) { // 分配设备号 alloc_chrdev_region(dev_num, 0, 1, my_device); // 初始化字符设备 cdev_init(my_cdev, my_fops); my_cdev.owner THIS_MODULE; // 添加字符设备 cdev_add(my_cdev, dev_num, 1); return 0; } // 模块退出 static void __exit my_exit(void) { // 移除字符设备 cdev_del(my_cdev); // 释放设备号 unregister_chrdev_region(dev_num, 1); } module_init(my_init); module_exit(my_exit); MODULE_LICENSE(GPL); MODULE_AUTHOR(Your Name); MODULE_DESCRIPTION(A simple character device driver);2. 块设备驱动#include linux/genhd.h #include linux/blkdev.h static int major_num; static struct gendisk *my_disk; static struct request_queue *my_queue; // 处理请求 static void my_request(struct request_queue *q) { struct request *req; req blk_fetch_request(q); while (req ! NULL) { // 处理请求 blk_end_request_all(req, 0); req blk_fetch_request(q); } } // 模块初始化 static int __init my_init(void) { // 分配主设备号 major_num register_blkdev(0, my_block); // 分配磁盘结构 my_disk alloc_disk(1); my_disk-major major_num; my_disk-first_minor 0; sprintf(my_disk-disk_name, myblock); my_disk-fops my_fops; // 创建请求队列 my_queue blk_init_queue(my_request, NULL); my_disk-queue my_queue; // 添加磁盘 add_disk(my_disk); return 0; } // 模块退出 static void __exit my_exit(void) { // 移除磁盘 del_gendisk(my_disk); put_disk(my_disk); // 释放请求队列 blk_cleanup_queue(my_queue); // 释放主设备号 unregister_blkdev(major_num, my_block); } module_init(my_init); module_exit(my_exit); MODULE_LICENSE(GPL); MODULE_AUTHOR(Your Name); MODULE_DESCRIPTION(A simple block device driver);3. 网络设备驱动#include linux/netdevice.h static struct net_device *my_netdev; // 打开网络设备 static int my_netdev_open(struct net_device *dev) { // 启用设备 netif_start_queue(dev); return 0; } // 关闭网络设备 static int my_netdev_stop(struct net_device *dev) { // 禁用设备 netif_stop_queue(dev); return 0; } // 发送网络数据包 static netdev_tx_t my_netdev_start_xmit(struct sk_buff *skb, struct net_device *dev) { // 发送数据包 dev_kfree_skb(skb); return NETDEV_TX_OK; } // 网络设备操作 static struct net_device_ops my_netdev_ops { .ndo_open my_netdev_open, .ndo_stop my_netdev_stop, .ndo_start_xmit my_netdev_start_xmit, }; // 模块初始化 static int __init my_init(void) { // 分配网络设备 my_netdev alloc_netdev(0, myeth%d, NET_NAME_UNKNOWN, ether_setup); // 设置设备操作 my_netdev-netdev_ops my_netdev_ops; // 注册网络设备 register_netdev(my_netdev); return 0; } // 模块退出 static void __exit my_exit(void) { // 注销网络设备 unregister_netdev(my_netdev); free_netdev(my_netdev); } module_init(my_init); module_exit(my_exit); MODULE_LICENSE(GPL); MODULE_AUTHOR(Your Name); MODULE_DESCRIPTION(A simple network device driver);设备驱动的注册与管理1. 设备号管理# 查看设备号 cat /proc/devices # 创建设备节点 mknod /dev/my_device c major minor # 查看设备节点 ls -l /dev/my_device2. 模块管理# 加载模块 insmod my_driver.ko # 查看模块 lsmod | grep my_driver # 查看模块信息 modinfo my_driver.ko # 卸载模块 rmmod my_driver3. 设备驱动的调试# 查看内核日志 dmesg | tail # 启用调试信息 echo 8 /proc/sys/kernel/printk # 使用ftrace trace-cmd record -e function_graph modprobe my_driver trace-cmd report设备驱动的高级特性1. 设备树// 设备树节点 /* my_device { compatible my,device; reg 0x10000000 0x1000; interrupts 10; }; */ // 设备树匹配 static const struct of_device_id my_of_match[] { { .compatible my,device, }, { }, }; MODULE_DEVICE_TABLE(of, my_of_match); // 平台驱动 static struct platform_driver my_driver { .probe my_probe, .remove my_remove, .driver { .name my_device, .of_match_table my_of_match, }, };2. 电源管理// 电源管理操作 static int my_suspend(struct device *dev) { // 实现挂起操作 return 0; } static int my_resume(struct device *dev) { // 实现恢复操作 return 0; } static const struct dev_pm_ops my_pm_ops { .suspend my_suspend, .resume my_resume, }; // 设置电源管理操作 static struct platform_driver my_driver { // 其他字段... .driver { // 其他字段... .pm my_pm_ops, }, };3. 异步通知// 异步通知 static struct fasync_struct *my_fasync; // 实现fasync操作 static int my_fasync(int fd, struct file *file, int on) { return fasync_helper(fd, file, on, my_fasync); } // 发送信号 static void send_signal(void) { kill_fasync(my_fasync, SIGIO, POLL_IN); } // 文件操作结构 static struct file_operations my_fops { // 其他操作... .fasync my_fasync, };设备驱动的性能优化1. 中断处理// 中断处理 static irqreturn_t my_irq_handler(int irq, void *dev_id) { // 快速处理 schedule_work(my_work); return IRQ_HANDLED; } // 工作队列 static struct work_struct my_work; static void my_work_handler(struct work_struct *work) { // 耗时处理 } // 初始化工作队列 INIT_WORK(my_work, my_work_handler); // 注册中断 request_irq(irq, my_irq_handler, IRQF_SHARED, my_device, dev_id);2. DMA传输// DMA缓冲区分配 static void *dma_buf; static dma_addr_t dma_addr; dma_buf dma_alloc_coherent(dev, size, dma_addr, GFP_KERNEL); // DMA传输 dmaengine_submit(tx); dma_async_issue_pending(chan); // 等待传输完成 dma_sync_single_for_cpu(dev, dma_addr, size, DMA_FROM_DEVICE); // 释放DMA缓冲区 dma_free_coherent(dev, size, dma_buf, dma_addr);3. 内存映射// 内存映射 static int my_mmap(struct file *file, struct vm_area_struct *vma) { vma-vm_flags | VM_IO; vma-vm_flags | VM_DONTEXPAND; vma-vm_flags | VM_DONTDUMP; if (io_remap_pfn_range(vma, vma-vm_start, pfn, vma-vm_end - vma-vm_start, vma-vm_page_prot)) { return -EAGAIN; } return 0; } // 文件操作结构 static struct file_operations my_fops { // 其他操作... .mmap my_mmap, };实际案例分析1. 字符设备驱动#include linux/module.h #include linux/fs.h #include linux/cdev.h #include linux/uaccess.h static dev_t dev_num; static struct cdev my_cdev; static char buffer[256]; static int my_open(struct inode *inode, struct file *file) { printk(KERN_INFO Device opened\n); return 0; } static ssize_t my_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { if (*pos sizeof(buffer)) return 0; if (*pos count sizeof(buffer)) count sizeof(buffer) - *pos; if (copy_to_user(buf, buffer *pos, count)) return -EFAULT; *pos count; return count; } static ssize_t my_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) { if (*pos sizeof(buffer)) return 0; if (*pos count sizeof(buffer)) count sizeof(buffer) - *pos; if (copy_from_user(buffer *pos, buf, count)) return -EFAULT; *pos count; return count; } static int my_release(struct inode *inode, struct file *file) { printk(KERN_INFO Device closed\n); return 0; } static struct file_operations my_fops { .owner THIS_MODULE, .open my_open, .read my_read, .write my_write, .release my_release, }; static int __init my_init(void) { if (alloc_chrdev_region(dev_num, 0, 1, my_device) 0) { printk(KERN_ERR Failed to allocate device number\n); return -1; } cdev_init(my_cdev, my_fops); my_cdev.owner THIS_MODULE; if (cdev_add(my_cdev, dev_num, 1) 0) { printk(KERN_ERR Failed to add device\n); unregister_chrdev_region(dev_num, 1); return -1; } printk(KERN_INFO Device driver loaded\n); return 0; } static void __exit my_exit(void) { cdev_del(my_cdev); unregister_chrdev_region(dev_num, 1); printk(KERN_INFO Device driver unloaded\n); } module_init(my_init); module_exit(my_exit); MODULE_LICENSE(GPL); MODULE_AUTHOR(Your Name); MODULE_DESCRIPTION(A simple character device driver);2. 网络设备驱动#include linux/module.h #include linux/netdevice.h #include linux/etherdevice.h static struct net_device *my_netdev; static int my_netdev_open(struct net_device *dev) { netif_start_queue(dev); printk(KERN_INFO Network device opened\n); return 0; } static int my_netdev_stop(struct net_device *dev) { netif_stop_queue(dev); printk(KERN_INFO Network device stopped\n); return 0; } static netdev_tx_t my_netdev_start_xmit(struct sk_buff *skb, struct net_device *dev) { dev-stats.tx_packets; dev-stats.tx_bytes skb-len; dev_kfree_skb(skb); return NETDEV_TX_OK; } static struct net_device_ops my_netdev_ops { .ndo_open my_netdev_open, .ndo_stop my_netdev_stop, .ndo_start_xmit my_netdev_start_xmit, }; static void my_netdev_setup(struct net_device *dev) { ether_setup(dev); dev-netdev_ops my_netdev_ops; eth_hw_addr_random(dev); dev-mtu 1500; dev-flags | IFF_NOARP; } static int __init my_init(void) { my_netdev alloc_netdev(0, myeth%d, NET_NAME_UNKNOWN, my_netdev_setup); if (!my_netdev) { printk(KERN_ERR Failed to allocate network device\n); return -ENOMEM; } if (register_netdev(my_netdev) 0) { printk(KERN_ERR Failed to register network device\n); free_netdev(my_netdev); return -1; } printk(KERN_INFO Network device driver loaded\n); return 0; } static void __exit my_exit(void) { unregister_netdev(my_netdev); free_netdev(my_netdev); printk(KERN_INFO Network device driver unloaded\n); } module_init(my_init); module_exit(my_exit); MODULE_LICENSE(GPL); MODULE_AUTHOR(Your Name); MODULE_DESCRIPTION(A simple network device driver);3. 设备驱动调试#!/bin/bash # 编译驱动 make # 加载驱动 insmod my_driver.ko # 创建设备节点 mknod /dev/my_device c $(grep my_device /proc/devices | awk {print $1}) 0 # 测试设备 echo Hello, World! /dev/my_device cat /dev/my_device # 查看内核日志 dmesg | tail # 卸载驱动 rmmod my_driver结论设备驱动是Linux内核中的重要组成部分它负责管理硬件设备与内核之间的通信。设备驱动为应用程序提供了访问硬件设备的接口使得应用程序可以无需了解硬件的具体实现细节。理解设备驱动的原理和实现对于系统编程、硬件开发和故障处理都有重要意义。随着硬件技术的不断发展设备驱动的复杂性也在不断增加成为现代操作系统设计的关键部分。

相关文章:

Linux内核中的设备驱动详解

Linux内核中的设备驱动详解 引言 设备驱动是Linux内核中的重要组成部分,它负责管理硬件设备与内核之间的通信。设备驱动为应用程序提供了访问硬件设备的接口,使得应用程序可以无需了解硬件的具体实现细节。本文将深入探讨Linux内核中的设备驱动机制&…...

Spring MVC 01

什么是Spring Web MVC Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架,从⼀开始就包含在 Spring 框架中。它的正式名称“Spring Web MVC”来⾃其源模块的名称(Spring-webmvc),但它通常被称为"Spring MVC" 然⽽要真正的理解什么是…...

AI 新闻周报 | 2026年4月12日-4月18日

AI 新闻周报 | 2026年4月12日-4月18日 📅 周期:2026年4月12日 - 4月18日 📝 一句话总结:大模型巨头密集发布旗舰产品,AI 安全与能力的博弈白热化;具身智能融资狂飙、工业落地加速;全球 AI 监管框…...

FairyGUI按钮动效实战:从点击缩放+音效到复杂转场,一个完整项目案例拆解

FairyGUI按钮动效实战:从点击反馈到复杂转场的全流程解决方案 在游戏界面开发中,按钮动效不仅仅是装饰,更是用户体验的关键组成部分。一个精心设计的按钮动效能够显著提升用户的操作反馈感,而流畅的界面转场则能增强应用的沉浸感…...

Hailo8 Dataflow Compiler 模型转换指南--以 ONNX 模型为例

目录 一、环境安装 1.1 系统要求 1.2 系统包安装 二、模型转换 2.1 ONNX 转 HEF 文件 2.1.1 实例化 ClientRunner 解析ONNX模型 2.2.2 加载/准备量化校准数据集 2.2.3 参数配置并执行量化操作 2.2.4 保存 HAR 文件并编译生成 HEF 板端文件 2.2 模型可视化 一、环境安…...

用python解放右手系列(三) Excel自动化-告别复制粘贴的噩梦

Excel 自动化:告别复制粘贴的噩梦本文基于 Python 3.9,涉及库:pandas、openpyxl。阅读时间约 12 分钟。 安装依赖:pip install pandas openpyxl每月 1 号的"酷刑" 阿明刚用 Python 搞定文件重命名,还没高兴两…...

MusePublic Art Studio生成多样性控制:潜在空间探索技术

MusePublic Art Studio生成多样性控制:潜在空间探索技术 说实话,用AI生成艺术图片,最让人头疼的可能不是“画不出来”,而是“画得都一样”。你输入一段描述,比如“一个赛博朋克风格的武士”,模型确实能给你…...

COMSOL 超表面仿真:从入门到“光速”出图!

在系统讲解天线、超表面的物理原理、功能实现机制以及利用有限元法(Finite Element Method, FEM)进行建模与仿真设计的完整流程。通过理论讲授与仿真实践相结合的方式,帮助学员掌握从结构建模、物理场设置、网格划分、参数扫描到仿真后处理与…...

低分辨率图像修复难题的终极解决方案:Upscayl深度技术解析

低分辨率图像修复难题的终极解决方案:Upscayl深度技术解析 【免费下载链接】upscayl 🆙 Upscayl - #1 Free and Open Source AI Image Upscaler for Linux, MacOS and Windows. 项目地址: https://gitcode.com/GitHub_Trending/up/upscayl 面对模…...

《Hermes Agent 代码库安全漏洞分析与解决办法》

Hermes Agent 代码库安全漏洞分析与解决办法 Hermes Agent 作为跨平台自改进型 AI 智能体框架,涉及配置管理、多端通信、工具调用、容器部署等核心环节,以下从配置安全、部署安全、代码执行风险、数据隐私、网络通信、依赖管理、权限控制七大维度&#x…...

计算机毕业设计:Python农产品电商数据采集与价格预估平台 Flask框架 Spark 线性回归 数据分析 可视化 大数据 大模型(建议收藏)✅

1、项目介绍 技术栈 采用 Python 语言开发,基于 Flask 框架搭建后端服务,使用 Spark 技术进行大数据处理,通过 requests 爬虫从惠农网采集农产品数据,运用线性回归预测算法模型进行价格预测,前端结合 Echarts 可视化库…...

Intv_AI_MK11 Node.js 环境集成教程:构建全栈智能应用

Intv_AI_MK11 Node.js 环境集成教程:构建全栈智能应用 1. 开篇:为什么选择Node.js集成AI能力 如果你是一名Node.js开发者,想要给自己的应用添加AI能力,这篇教程就是为你准备的。我们将一步步带你完成从零开始的环境搭建&#xf…...

三分钟快速定位:Windows热键冲突终极解决方案指南

三分钟快速定位:Windows热键冲突终极解决方案指南 【免费下载链接】hotkey-detective A small program for investigating stolen key combinations under Windows 7 and later. 项目地址: https://gitcode.com/gh_mirrors/ho/hotkey-detective 你是否曾经按…...

从单兵到军团:2026 多智能体协作的崛起与实战全指南

从单兵到军团:2026 多智能体协作的崛起与实战全指南在前三篇文章中,我们拆解了单个AI Agent的技术内核,并盘点了2026年主流框架的选型策略。但企业级场景的复杂程度,正在以肉眼可见的速度超越单一个体的能力天花板。单个“全能实习…...

Cursor AI免费VIP破解方案:如何绕过试用限制持续使用Pro功能

Cursor AI免费VIP破解方案:如何绕过试用限制持续使用Pro功能 【免费下载链接】cursor-free-vip [Support 0.45](Multi Language 多语言)自动注册 Cursor Ai ,自动重置机器ID , 免费升级使用Pro 功能: Youve reached yo…...

PD协议中的VDM:从握手到模式切换的实战解析

1. VDM基础:从USB PD到厂商自定义消息 第一次接触USB PD协议中的VDM(Vendor Defined Message)时,我完全被各种缩写搞晕了。后来在实际项目中调试一个支持DisplayPort Alt Mode的扩展坞才发现,VDM简直是USB-C设备的&qu…...

在 Linux 中查询最耗费 CPU 资源的前 10 个进程的常用脚本

方法一:使用 ps 命令(推荐,最通用)#!/bin/bash # 查看CPU占用最高的10个进程 ps aux --sort-%cpu | head -n 11 | tail -n 10或者更详细的版本:#!/bin/bash echo " CPU使用率最高的10个进程 " printf "…...

051.数据库选型:为检测结果存储选择合适的数据库(SQLite/MySQL/PostgreSQL)

从一次线上事故说起 上个月深夜接到报警,部署在厂区的YOLO检测服务突然响应缓慢。登录服务器一看,发现检测结果写入数据库的线程全部卡死,前端页面加载历史记录要十几秒。查日志定位到问题:随着检测图片数量突破百万级,当初为了省事直接用的SQLite文件膨胀到8GB,并发写入…...

零代码经验也能搞定的软著申请:用AI工具30分钟生成合规材料

零代码经验也能搞定的软著申请:用AI工具30分钟生成合规材料 在数字化浪潮席卷各行各业的今天,软件著作权(简称"软著")已成为保护创新成果的重要法律凭证。无论是初创企业的核心产品、高校科研项目的技术输出&#xff0c…...

真的绝了!这套私域运营思路和方法让我效率提升10倍

你有没有发现,很多人做私域,每天花4.5小时在重复劳动上——回消息2小时、写朋友圈1小时、手动拉群0.5小时、跟进客户1小时。一年下来1642.5个小时,折合68天。结果呢?好友从3000删到800,月成交从50单跌到8单&#xff0c…...

Shopee卖家必看:如何用爬虫自动监控竞品评价与价格(Python实战)

Shopee卖家必看:如何用Python爬虫实现竞品评价与价格智能监控 在东南亚电商市场激烈竞争的今天,Shopee卖家们面临着一个共同的挑战:如何快速响应市场变化,及时调整运营策略?传统的人工监控方式不仅效率低下&#xff0…...

Flutter 三方库 serial 的鸿蒙化适配指南—如何在在鸿蒙系统上构建极致、稳定的 Web 串口通信与工业硬软连接实战

在工业数字化、设备物联网化、产线可视化运维的场景里,串口通信依然是最基础、最稳定、最具成本优势的设备连接方式之一。无论是 PLC、仪器仪表、扫码枪、称重模块,还是自定义 MCU 控制板,大量设备仍通过 UART/USB-Serial 与上位系统交换数据…...

C++数据成员指针

class Data1 { public:int a;char b; };int Data1:: * aa &Data1::a; 这行代码定义了一个指向 Data1 类中 int 类型成员变量的指针 aa,并将其初始化为指向成员 a。 int Data1::* 是指向 Data1 类中 int 类型数据成员的指针类型。aa 是指针变量的名字。&Dat…...

OpenGL渲染与几何内核那点事-项目实践理论补充(一-3-(6):从“搬砖”到“无人仓”:一个CAD极客的OpenGL性能压榨史,连AI都看呆了——给图形学新手的VBO/VAO全攻略)

TOC 代码仓库入口: github源码地址。gitee源码地址。 系列文章规划: OpenGL渲染与几何内核那点事-项目实践理论补充(一-1-(8)-番外篇:当你的 CAD 遇上“活”的零件)OpenGL渲染与几何内核那点事-项目实践理论补充(一-2-(1)-当你的CAD想“联…...

Fish-Speech 1.5新手必看:3个参数调出完美语音,告别重复卡顿

Fish-Speech 1.5新手必看:3个参数调出完美语音,告别重复卡顿 1. 为什么你的语音合成总是不自然? 刚接触语音合成的朋友经常会遇到这样的困扰:生成的语音要么机械感十足,要么频繁重复字词,甚至出现莫名其妙…...

【2024 AGI技术成熟度白皮书】:12项核心指标首次量化评估,仅2项达Gartner Hype Cycle峰值前夜

第一章:AGI的技术瓶颈与突破方向 2026奇点智能技术大会(https://ml-summit.org) 当前通用人工智能(AGI)仍受限于认知架构的不完备性、跨域迁移的脆弱性以及因果推理的符号—神经鸿沟。尽管大语言模型在模式覆盖上取得显著进展,其…...

跨时钟域处理方法

目录前言1.1 setup-time 和 hold-time1.2 亚稳态的产生及原因2. 单bit信号跨时钟域处理方法2.1 慢时钟域到快时钟域-打两拍2.2 快时钟域到慢时钟域-脉冲同步前言 1.1 setup-time 和 hold-time 同步时序电路设计中,只在时钟的上升沿或下降沿进行采样。为了正确得到…...

Python的__init_subclass__类装饰器链式调用与元类协作

Python的类装饰器与元类机制一直是其面向对象编程中的高级特性,而__init_subclass__的引入进一步丰富了类层次结构的控制能力。当开发者需要在不显式使用元类的情况下定制子类行为,或实现装饰器链式调用与元类的协作时,这一特性展现出强大的灵…...

G-Helper终极指南:5分钟掌握华硕笔记本性能优化技巧

G-Helper终极指南:5分钟掌握华硕笔记本性能优化技巧 【免费下载链接】g-helper Lightweight, open-source control tool for ASUS laptops and ROG Ally. Manage performance modes, fans, GPU, battery, and RGB lighting across Zephyrus, Flow, TUF, Strix, Scar…...

【JVM深度解析】第24篇:JVM内存模型(JMM)核心原理

摘要 JMM(Java Memory Model,Java 内存模型)是 Java 并发编程的基础,它定义了线程之间共享变量的可见性、有序性问题,以及如何通过 Happens-Before 规则和内存屏障来解决这些问题。理解 JMM,你才能真正明白…...