6ull驱动记录--字符设备驱动开发基本框架

2024-08-30 14:20

本文主要是介绍6ull驱动记录--字符设备驱动开发基本框架,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1、字符设备驱动开发

1.1 字符设备

字符设备是Linux驱动中最基本的设备驱动,所谓的字符设备就是按照字节流(一个一个字节)进行读写操作的设备。常见的字符设备有点灯、LED、按键、IIC、SPI、LCD等等。

1.2 字符设备的实现

要实现一个字符设备程序,需要包括驱动模块加载、字符设备、实现的具体操作函数、LICENSE

1.2.1 驱动模块的加载和卸载

函数介绍:

Linux 驱动有两种运行方式:

第一种是将驱动编译进 Linux 内核中,这样当 Linux 内核启动的时候就会自动运行驱动程序。

第二种是将驱动编译成模块(Linux 下模块扩展名为.ko),在Linux 内核启动以后使用“insmod”命令加载驱动模块。(常用)

模块有加载和卸载两种操作,我们在编写驱动的时候需要注册这两种操作函数,模块的加载和卸载注册函数如下

module_init(xxx_init); //注册模块加载函数 
module_exit(xxx_exit); //注册模块卸载函数
说明:

module_init 函数用来向 Linux 内核注册一个模块加载函数,参数 xxx_init 就是需要注册的具体函数,当使用“insmod”命令加载驱动的时候,xxx_init 这个函数就会被调用。

module_exit()函数用来向 Linux 内核注册一个模块卸载函数,参数 xxx_exit 就是需要注册的具体函数,当使用“rmmod”命令卸载具体驱动的时候 xxx_exit 函数就会被调用。

使用:
/* 驱动入口函数 */ 
static int __init xxx_init(void) 
{ 
/* 入口函数具体内容 */ 
return 0; } 
/* 驱动出口函数 */ 
static void __exit xxx_exit(void) 
{ 
/* 出口函数具体内容 */ 
} 
/* 将上面两个函数指定为驱动的入口和出口函数 类似于声明*/ 
module_init(xxx_init); 
module_exit(xxx_exit);

1.2.2 字符设备的注册和注销

函数介绍:

加载驱动模块之后需要注册字符设备和注销字符设备,函数模型:

static inline int register_chrdev(unsigned int major, const char *name, 
const struct file_operations *fops) 
static inline void unregister_chrdev(unsigned int major, const char *name) 

major:主设备号,Linux 下每个设备都有一个设备号,设备号分为主设备号和次设备号两部分。

name:设备名字,指向一串字符串。

fops:结构体 file_operations 类型指针,指向设备的操作函数集合变量。

使用:
static struct file_operations fops_test;
/* 驱动入口函数 */ 
static int __init xxx_init(void) 
{ 
/* 入口函数具体内容 */ int retvalue =0 ;retvalue = register_chrdev(200,"test_dev",fops_test);if(retvalue < 0){//创建失败处理}
return 0; } 
/* 驱动出口函数 */ 
static void __exit xxx_exit(void) 
{ 
/* 出口函数具体内容 */unregister_chrdev(200,"test_dev"); 
} 
/* 将上面两个函数指定为驱动的入口和出口函数 类似于声明*/ 
module_init(xxx_init); 
module_exit(xxx_exit);
设备号说明

Linux 中每个设备都有一个设备号,设备号由主设备号(12位)和次设备号(20位)两部分组成

1、主设备号表示某一个具体的驱动:比如LED、按键设备、adc设备等

2、次设备号表示使用这个驱动的各个设备:比如LED1,LED2、、、等

因此 Linux系统中主设备号范围为 0~4095

当有两个设备,主设备号一样,次设备号不同,会有两个设备节点。

1.2.3 实现设备的具体操作函数-file_operations

函数介绍

file_operations 的结构体是Linux 内核驱动操作函数集合:

struct file_operations {struct module *owner;loff_t (*llseek) (struct file *, loff_t, int);ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);int (*iterate) (struct file *, struct dir_context *);unsigned int (*poll) (struct file *, struct poll_table_struct *);long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);long (*compat_ioctl) (struct file *, unsigned int, unsigned long);int (*mmap) (struct file *, struct vm_area_struct *);int (*mremap)(struct file *, struct vm_area_struct *);int (*open) (struct inode *, struct file *);int (*flush) (struct file *, fl_owner_t id);int (*release) (struct inode *, struct file *);int (*fsync) (struct file *, loff_t, loff_t, int datasync);int (*aio_fsync) (struct kiocb *, int datasync);int (*fasync) (int, struct file *, int);int (*lock) (struct file *, int, struct file_lock *);ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);int (*check_flags)(int);int (*flock) (struct file *, int, struct file_lock *);ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);int (*setlease)(struct file *, long, struct file_lock **, void **);long (*fallocate)(struct file *file, int mode, loff_t offset,loff_t len);void (*show_fdinfo)(struct seq_file *m, struct file *f);
#ifndef CONFIG_MMUunsigned (*mmap_capabilities)(struct file *);
#endif
};
使用

假设应用程序需要通过 read 和 write 这两个函数进行读写操作,所以需要实现 file_operations 中的 read 和 write 这两个函数。


/* 打开设备 */ 
static int chrtest_open(struct inode *inode, struct file *filp) 
{ /* 用户实现具体功能 */ return 0; } /* 从设备读取 */ 
static ssize_t chrtest_read(struct file *filp, char __user *buf,  size_t cnt, loff_t *offt) 
{ /* 用户实现具体功能 */ return 0; } /* 向设备写数据 */ static ssize_t chrtest_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt) { /* 用户实现具体功能 */ return 0; } /* 关闭/释放设备 */ static int chrtest_release(struct inode *inode, struct file *filp) { /* 用户实现具体功能 */  return 0; } static struct file_operations test_fops = { .owner = THIS_MODULE,  .open = chrtest_open, .read = chrtest_read, .write = chrtest_write, .release = chrtest_release, 
}; 
/* 驱动入口函数 */ 
static int __init xxx_init(void) 
{ /* 入口函数具体内容 */ int retvalue = 0; /* 注册字符设备驱动 */ retvalue = register_chrdev(200, "chrtest", &test_fops); if(retvalue < 0){ /* 字符设备注册失败,自行处理 */ } return 0; 
} 
/* 驱动出口函数 */ 
static void __exit xxx_exit(void) 
{ /* 注销字符设备驱动 */ unregister_chrdev(200, "chrtest"); } /* 将上面两个函数指定为驱动的入口和出口函数 */ module_init(xxx_init); module_exit(xxx_exit); 

1.2.4 添加 LICENSE 和作者信息

在文章最后加入 LICENSE 信息和作者信息

LICENSE 是必须添加的,否则的话编译的时候会报错(脏内核)

作者信息可以添加也可以不添加

MODULE_LICENSE("GPL") //添加模块 LICENSE 信息 
MODULE_AUTHOR("zhaorming") //添加模块作者信息 

2、整体

static struct file_operations test_fops;
/* 打开设备 */ 
static int chrtest_open(struct inode *inode, struct file *filp) 
{ /* 用户实现具体功能 */ return 0; } /* 从设备读取 */ 
static ssize_t chrtest_read(struct file *filp, char __user *buf,  size_t cnt, loff_t *offt) 
{ /* 用户实现具体功能 */ return 0; } /* 向设备写数据 */ static ssize_t chrtest_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt) { /* 用户实现具体功能 */ return 0; } /* 关闭/释放设备 */ static int chrtest_release(struct inode *inode, struct file *filp) { /* 用户实现具体功能 */  return 0; } static struct file_operations test_fops = { .owner = THIS_MODULE,  .open = chrtest_open, .read = chrtest_read, .write = chrtest_write, .release = chrtest_release, 
}; 
/* 驱动入口函数 */ 
static int __init xxx_init(void) 
{ /* 入口函数具体内容 */ int retvalue = 0; /* 注册字符设备驱动 */ retvalue = register_chrdev(200, "chrtest", &test_fops); if(retvalue < 0){ /* 字符设备注册失败,自行处理 */ } return 0; 
} 
/* 驱动出口函数 */ 
static void __exit xxx_exit(void) 
{ /* 注销字符设备驱动 */ unregister_chrdev(200, "chrtest"); } /* 将上面两个函数指定为驱动的入口和出口函数 */ module_init(xxx_init); module_exit(xxx_exit); MODULE_LICENSE("GPL") //添加模块 LICENSE 信息 MODULE_AUTHOR("zhaorming") //添加模块作者信息 

这篇关于6ull驱动记录--字符设备驱动开发基本框架的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1121064

相关文章

SpringBoot集成图片验证码框架easy-captcha的详细过程

《SpringBoot集成图片验证码框架easy-captcha的详细过程》本文介绍了如何将Easy-Captcha框架集成到SpringBoot项目中,实现图片验证码功能,Easy-Captcha是... 目录SpringBoot集成图片验证码框架easy-captcha一、引言二、依赖三、代码1. Ea

Gin框架中的GET和POST表单处理的实现

《Gin框架中的GET和POST表单处理的实现》Gin框架提供了简单而强大的机制来处理GET和POST表单提交的数据,通过c.Query、c.PostForm、c.Bind和c.Request.For... 目录一、GET表单处理二、POST表单处理1. 使用c.PostForm获取表单字段:2. 绑定到结

Spring Retry 实现乐观锁重试实践记录

《SpringRetry实现乐观锁重试实践记录》本文介绍了在秒杀商品SKU表中使用乐观锁和MybatisPlus配置乐观锁的方法,并分析了测试环境和生产环境的隔离级别对乐观锁的影响,通过简单验证,... 目录一、场景分析 二、简单验证 2.1、可重复读 2.2、读已提交 三、最佳实践 3.1、配置重试模板

在 Spring Boot 中使用异步线程时的 HttpServletRequest 复用问题记录

《在SpringBoot中使用异步线程时的HttpServletRequest复用问题记录》文章讨论了在SpringBoot中使用异步线程时,由于HttpServletRequest复用导致... 目录一、问题描述:异步线程操作导致请求复用时 Cookie 解析失败1. 场景背景2. 问题根源二、问题详细分

Android开发中gradle下载缓慢的问题级解决方法

《Android开发中gradle下载缓慢的问题级解决方法》本文介绍了解决Android开发中Gradle下载缓慢问题的几种方法,本文给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录一、网络环境优化二、Gradle版本与配置优化三、其他优化措施针对android开发中Gradle下载缓慢的问

C# string转unicode字符的实现

《C#string转unicode字符的实现》本文主要介绍了C#string转unicode字符的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随... 目录1. 获取字符串中每个字符的 Unicode 值示例代码:输出:2. 将 Unicode 值格式化

Python中多线程和多进程的基本用法详解

《Python中多线程和多进程的基本用法详解》这篇文章介绍了Python中多线程和多进程的相关知识,包括并发编程的优势,多线程和多进程的概念、适用场景、示例代码,线程池和进程池的使用,以及如何选择合适... 目录引言一、并发编程的主要优势二、python的多线程(Threading)1. 什么是多线程?2.

使用Go语言开发一个命令行文件管理工具

《使用Go语言开发一个命令行文件管理工具》这篇文章主要为大家详细介绍了如何使用Go语言开发一款命令行文件管理工具,支持批量重命名,删除,创建,移动文件,需要的小伙伴可以了解下... 目录一、工具功能一览二、核心代码解析1. 主程序结构2. 批量重命名3. 批量删除4. 创建文件/目录5. 批量移动三、如何安

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解

《如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解》:本文主要介绍如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别的相关资料,描述了如何使用海康威视设备网络SD... 目录前言开发流程问题和解决方案dll库加载不到的问题老旧版本sdk不兼容的问题关键实现流程总结前言作为