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

linux实现设备驱动-字符型设备驱动

一、linux驱动分类

(1)字符设备驱动 (Character Device Driver):

  • 特点: 数据按字节流 (byte stream) 形式访问,即数据访问有严格的顺序性。
  • 数据传输为字节流形式,顺序读写,不带缓存,无固定块大小。
  • 通常采用中断驱动或轮询方式处理 I/O 请求,响应实时性较强。
  • 设备节点通常位于 /dev 目录下,通过文件描述符进行操作。
  • 示例: LED灯、按键、串口(UART)等,输入输出设备(鼠标、键盘、屏幕、摄像头)
  • 管理方式: 通过设备号 (Device Number) 管理。

(2)块设备驱动 (Block Device Driver):

  • 特点: 数据以固定大小的块 (block)(大小为512k) 为单位进行访问,带缓存,通常用于存储设备。
  • 示例: 硬盘、SSD、U盘等。访问时可以随机读取任意位置的数据,不受顺序限制。
  • 管理方式: 通过设备号 (Device Number) 管理。

(3)网络设备驱动 (Network Device Driver):

  • 特点: 集成复杂的协议栈 (Protocol Stack),如TCP/IP、UDP等。
  • 示例: 网卡。
  • 管理方式: 按照名字 (Name) 管理,如 ens33

(1)字符型设备驱动:

1.字符型设备驱动不自动生成设备节点(‘myled)
  • 手动创建设备节点 :(在开发板中创建)

①前提条件:开发板已运行 Linux 内核,且需知道目标设备的主设备号次设备号(可通过内核日志dmesg或驱动代码获取)。

③验证与权限设置:

  • 自动生成设备节点 class_create() device_create()

在init函数中调用class_createdevice_create接口,结合sysfs自动生成设备节点。

2.设备号 (Device Number):设备号是内核用于管理驱动设备的一个32位无符号整数 (u32)。它被划分为两部分:

  • 主设备号 (Major Number): 高12位,用于区分设备类型。例如,所有LED灯使用同一个主设备号,所有按键使用另一个主设备号。
  • 次设备号 (Minor Number): 低20位,用于区分同一类型设备中的不同个体。例如,4个LED灯分别使用不同的次设备号(0, 1, 2, 3)。

(2)嵌入式 Linux 设备驱动调用流程示意图分析:

1.用户应用层(user app)

  • 应用程序通过open(led)fopen(led)发起设备操作请求,依赖libc库将请求转换为系统调用。

2. 根文件系统层(rootfs)

  • 设备节点(如led_1key_2uart_3)存在于 /dev 目录,是用户层与驱动层的交互入口。

3. 系统调用与驱动管理层

  • 系统调用syscall_open(led)将用户请求传入内核,内核通过设备号匹配对应的驱动(如 LED 驱动匹配设备号 1)。
  • 内核驱动管理模块(含open操作与驱动索引 “1、2、3”)负责分发请求到具体驱动。

4. 设备驱动层

  • 包含LED_DRVKEY_DRVUART_DRV三类字符设备驱动,是硬件操作的直接实现层,完成如 LED 点亮、按键检测、串口数据收发等具体功能。

5. 硬件设备层

  • 对应实际硬件(LED、KEY、UART),驱动通过硬件寄存器、中断等机制完成物理层操作。

(3)字符型设备驱动开发流程:

将驱动程序写在内核顶层目录/driver/char目录下:

1.Linux 内核模块的 “标准注册接口”:

确保驱动能被内核正确加载和卸载,是字符设备驱动(如示例中的 LED 驱动)模块化管理的关键实现。

2.确定设备号,设备名称:

为驱动程序分配一个唯一的设备号。通常,主设备号从较大的数字开始分配(如255),因为较小的号码已被系统占用。

// 定义主设备号、次设备号和设备名称
#define MAJOR_NUM 248 // 主设备号
#define MINOR_NUM 0   // 次设备号
#define DEV_NAME "led1" // 设备名称

3.定义并实现操作方法 (file_operations结构体)

定义一个 struct file_operations 结构体(驱动层操作函数集合),其中包含指向驱动程序具体操作函数的指针,如 openreadwriterelease (close)。

// 声明操作函数原型
static int open(struct inode *node, struct file *file);
static ssize_t read(struct file *file, char __user *buf, size_t len, loff_t *loff);
static ssize_t write(struct file *file, const char __user *buf, size_t len, loff_t *loff);
static int close(struct inode *node, struct file *file);// 定义并初始化 file_operations 结构体
static struct file_operations fops = {.owner = THIS_MODULE, // 指向当前模块,用于防止模块在被引用时被卸载.open = open,         // 绑定 open 函数.read = read,         // 绑定 read 函数.write = write,       // 绑定 write 函数.release = close      // 绑定 release (close) 函数
};

4. 定义一个cdev结构体:

描述字符型设备相关的信息(设备号、设备名称...),绑定设备号与操作方法

static dev_t devno;          // 设备号变量
static struct cdev cdev;     // cdev 结构体实例// 在模块初始化函数中执行绑定
static int __init led1_init(void)
{int ret = 0;// 1. 使用 MKDEV 宏组合主、次设备号devno = MKDEV(MAJOR_NUM, MINOR_NUM);// 2. 初始化 cdev 结构体,关联操作方法cdev_init(&cdev, &fops);// 3. 将 cdev 添加到内核中,指定设备号和数量ret = cdev_add(&cdev, devno, 1);if(ret < 0)goto err_cdev_add; // 错误处理...
}

5.实现对应init函数(向内核注册驱动入口函数 insmod xxx.ko)

注册字符型设备

  • 静态注册:register_chrdev_region(使用预先定义的 MAJOR_NUM 和 MINOR_NUM 向内核申请设备号范围)
  • 动态注册:alloc_chrdev_region(如果静态省请未成功,系统自动分配一个未被占用的设备号)

②初始化cdev结构体:

③将cdev结构体添加到系统

④自动生成设备节点:

6.驱动层实现硬件交互逻辑read/write等接口中,通过寄存器操作、中断处理或 DMA 完成硬件数据读写。

7.注销与清理:实现对应exit函数(驱动注销函数 rmmod xxx

①注销字符型设备unregister_chrdev_region();

注销cdev结构体 :cdev_del();

删除类和设备节点 class_destroy() ;device_destroy()

④释放硬件资源 :iounmap();

8.应用程序调用流程

用户程序通过标准库函数(如 openreadwrite)发起系统调用,最终由内核调用驱动程序中对应的函数。

// 用户空间应用程序 (led1_app.c)
int main(int argc, const char *argv[])
{int fd = open("/dev/led1", O_RDWR); // 调用 open 系统调用if(fd < 0) { /* 错误处理 */ }write(fd, "ledon", 5);  // 调用 write 系统调用write(fd, "ledoff", 6); // 调用 write 系统调用close(fd); // 调用 close 系统调用return 0;
}

编写驱动→配置 Makefile,Kconfig→动态编译生成.ko→加载测试→(可选)集成到内核

http://www.dtcms.com/a/557239.html

相关文章:

  • 门户网站排版有引导的网站
  • Linux USB 子系统深度解析
  • Linux time function in C/C++【2】
  • 人工智能学习中深度学习之python基础之迭代器、生成器、文件处理和模块等
  • wordpress显示评论数福建企业seo推广
  • 12.C++:模版进阶
  • 大模型训练评估中的交叉验证详解
  • 变更股东怎样在工商网站做公示做网站的收费标准
  • (142页PPT)立白MES解决方案1Wonderware运营管理平台(附下载方式)
  • 机器学习日报10
  • Linux 2.6.10 调度器负载均衡机制深度解析:从理论到实现
  • 访链家网网站开发嘉定房地产网站建设
  • 多商户商城APP源码开发的未来方向:云原生、电商中台与智能客服
  • Liunx线程安全
  • 基于数据增强与对抗学习的门诊电子病历(EMR)文本分类python编程
  • 企业网站seo推广技巧建设视频网站设计意义
  • VSCode的插件配置同步到gitee
  • 短剧广告联盟 APP 用户画像:基于观看行为的广告精准投放模型
  • 找快照网站查询网站建设博采
  • [论文阅读] AI+ | AI如何重塑审计行业?从“手工筛查”到“智能决策”:AI审计的核心逻辑与未来路径
  • 论文精读:A review on multi-view learning(多视图学习综述)
  • 长宁制作网站网站建设属于会计哪个科目
  • 波动率建模(三)Heston模型及其Python实现
  • 左侧 导航 网站泰安信誉好的网络推广公司
  • python 初学2
  • 51单片机基础-LCD12864液晶显示
  • 在openSUSE-Leap-15.6-DVD-x86_64-Media自制应用软件离线包——备份91个视频解码器的rpm包
  • 《云原生基础设施》
  • dedecms手机网站开发怎么在网站底部添加备案号
  • 2019个人建网站利用关键词进网站后台