Linux字符设备驱动通用模板

字符驱动模板介绍

编写Linux字符设备驱动,核心是实现file_operations里面的函数,通过编写这些函数让设备驱动实现读写等相关操作。通过系统调用函数,实现用户层和内核的数据交互。从而实现应用程序通过驱动对硬件进行操作。

实现file_operations 结构体

实现这个结构体的owner成员一般默认配置为THIS_MODULE。这个成员是必不可少的。
后面的函数分别对应打开、读、写和关闭驱动的操作。在驱动编写中,需要将自己的函数名作为参数传给相应的成员,例如chrdevbase_open这个函数对应的是在打开这个驱动时所做的操作,因此需要将这个函数名传给open这个成员。需要注意的是在驱动中关闭函数对应的是release成员。在file_operations结构体中还有许多函数本文没有涉及,但实现的方法类似。

static struct file_operations chrdevbase_fops = {
	.owner = THIS_MODULE,	
	.open = chrdevbase_open,
	.read = chrdevbase_read,
	.write = chrdevbase_write,
	.release = chrdevbase_release,
};

驱动出入口函数

在驱动挂载和移除时所需要执行的操作函数叫做驱动的入口函数和出口函数。一般这两个函数承载着注册字符设备和注销字符设备的任务。注意,出口函数和入口函数需要将函数名作为参数传入module_init()和module_exit()这两个系统函数中,这样在挂载和移除设备驱动时才会执行相应的函数,具体实现如下。

module_init(chrdevbase_init);
module_exit(chrdevbase_exit);

函数

打开驱动函数

/*
 * @description		: 打开设备
 * @param - inode 	: 传递给驱动的inode
 * @param - filp 	: 设备文件,file结构体有个叫做private_data的成员变量
 * 					  一般在open的时候将private_data指向设备结构体。
 * @return 			: 0 成功;其他 失败
 */
static int chrdevbase_open(struct inode *inode, struct file *filp)
{
	//printk("chrdevbase open!\r\n");
	return 0;
}

读取设备数据

该函数通过调用memcpy()函数,将内核态的数组kerneldata[]中的数据拷贝出来,从而实现用户程序获取内核态的数据。

/*
 * @description		: 从设备读取数据 
 * @param - filp 	: 要打开的设备文件(文件描述符)
 * @param - buf 	: 返回给用户空间的数据缓冲区
 * @param - cnt 	: 要读取的数据长度
 * @param - offt 	: 相对于文件首地址的偏移
 * @return 			: 读取的字节数,如果为负值,表示读取失败
 */
static ssize_t chrdevbase_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
	int retvalue = 0;
	
	/* 向用户空间发送数据 */
	memcpy(readbuf, kerneldata, sizeof(kerneldata));
	retvalue = copy_to_user(buf, readbuf, cnt);
	if(retvalue == 0){
		printk("kernel senddata ok!\r\n");
	}else{
		printk("kernel senddata failed!\r\n");
	}
	
	//printk("chrdevbase read!\r\n");
	return 0;
}

向设备写入数据

/*
 * @description		: 向设备写数据 
 * @param - filp 	: 设备文件,表示打开的文件描述符
 * @param - buf 	: 要写给设备写入的数据
 * @param - cnt 	: 要写入的数据长度
 * @param - offt 	: 相对于文件首地址的偏移
 * @return 			: 写入的字节数,如果为负值,表示写入失败
 */
static ssize_t chrdevbase_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
	int retvalue = 0;
	/* 接收用户空间传递给内核的数据并且打印出来 */
	retvalue = copy_from_user(writebuf, buf, cnt);
	if(retvalue == 0){
		printk("kernel recevdata:%s\r\n", writebuf);
	}else{
		printk("kernel recevdata failed!\r\n");
	}
	
	//printk("chrdevbase write!\r\n");
	return 0;
}

关闭/释放设备

/*
 * @description		: 关闭/释放设备
 * @param - filp 	: 要关闭的设备文件(文件描述符)
 * @return 			: 0 成功;其他 失败
 */
static int chrdevbase_release(struct inode *inode, struct file *filp)
{
	//printk("chrdevbase release!\r\n");
	return 0;
}

驱动入口函数

/*
 * @description	: 驱动入口函数 
 * @param 		: 无
 * @return 		: 0 成功;其他 失败
 */
static int __init chrdevbase_init(void)
{
	int retvalue = 0;

	/* 注册字符设备驱动 */
	retvalue = register_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME, &chrdevbase_fops);
	if(retvalue < 0){
		printk("chrdevbase driver register failed\r\n");
	}
	printk("chrdevbase init!\r\n");
	return 0;
}

驱动出口函数

/*
 * @description	: 驱动出口函数
 * @param 		: 无
 * @return 		: 无
 */
static void __exit chrdevbase_exit(void)
{
	/* 注销字符设备驱动 */
	unregister_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME);
	printk("chrdevbase exit!\r\n");
}

添加模块的许可证声明

MODULE_LICENSE("GPL");
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
共计8个压缩包 本压缩包是:part06.rar 出版社:人民邮电出版社 ·页码:368 页 ·出版日期:2008年 ·ISBN:7115187118/9787115187116 ·条形码:9787115187116 ·包装版本:1版 ·装帧:平装 ·开本:16 ·中文:中文 ·附带品描述:附光盘一张 ·市场价格:49元 内容简介 Linux内核是Linux操作系统中最核心的部分,用于实现对硬件部件的编程控制和接口操作。《Linux2.6内核标准教程》深入、系统地讲解了 Linux内核的工作原理,对Linux内核的核心组件逐一进行深入讲解。 全书共8章,首先讲解Linux系统的引导过程;然后对Linux内核的3大核心模块——内存管理、进程管理、中断和异常处理进行了深入的分析; 在此基础上,对时间度量、系统调用进行了分析和讨论;最后讲解了Linux内核中常见的同步机制,使读者掌握每处理器变量和RCU这两种新的 同步机制。 《Linux2.6内核标准教程》适合Linux内核爱好者、Linux驱动开发人员、Linux系统工程师参考使用,也可以作为计算机及相关专业学生深入学 习操作系统的参考书。 引用: 目录 第1章 Linux内核学习基础 1 1.1 为什么研究Linux内核 2 1.1.1 Linux的历史来源 2 1.1.2 Linux的发展现状 3 1.1.3 Linux的前景展望 3 1.2 选择什么版本进行研究 3 1.3 内核基本结构 4 1.3.1 内核在操作系统中的地位 4 1.3.2 Linux 2.6内核源代码目录树简介 5 1.3.3 Linux 2.6内核的新特性 8 1.4 如何阅读本书 9 1.4.1 内核探索工具 10 1.4.2 推荐阅读方法 12 第2章 引导过程分析 14 2.1 内核镜像的构建过程 15 2.1.1 编译内核的步骤及分析 15 2.1.2 内核镜像构建过程分析 16 2.2 系统引导过程分析 18 2.2.1 傀儡引导扇区 18 2.2.2 探测系统资源 21 2.2.3 解压内核镜像 35 2.2.4 进入保护模式 40 2.2.5 系统最终初始化 47 2.3 系统引导过程总结 47 第3章 内存管理 50 3.1 基础知识 51 3.1.1 存储器地址 51 3.1.2 分段机制 52 3.1.3 分页机制 59 3.2 内核页表的初始化过程 65 3.2.1 启用分页机制 65 3.2.2 构建内核页表 68 3.3 物理内存的描述方法 76 3.3.1 内存节点 77 3.3.2 内存区域 81 3.3.3 物理页框 85 3.4 物理内存的初始化过程 86 3.4.1 探测系统物理内存 87 3.4.2 初始化内存分配器 89 3.5 物理内存的分配与回收 101 3.5.1 伙伴分配算法 101 3.5.2 对象缓冲技术 103 3.6 内核地址空间 105 3.6.1 常规映射地址空间 105 3.6.2 固定映射地址空间 107 3.6.3 长久内核映射空间 109 3.6.4 临时内核映射空间 116 3.6.5 非连续映射地址空间 119 第4章 进程管理 128 4.1 进程与线程的概念 129 4.1.1 程序与进程 129 4.1.2 进程与线程 129 4.2 进程描述符 131 4.2.1 进程标识符 132 4.2.2 进程的状态 132 4.2.3 进程上下文 134 4.2.4 当前进程 139 4.3 进程的组织形式 143 4.3.1 进程标识符构成的哈希表 143 4.3.2 所有进程构成的双向链表 148 4.3.3 执行态进程组成的运行队列 149 4.3.4 阻塞态进程组成的等待队列 152 4.4 进程的创建过程 155 4.4.1 进程创建的接口函数 156 4.4.2 进程创建的处理过程 162 4.5 进程调度算法 177 4.5.1 进程的分类 178 4.5.2 进程优先级 178 4.5.3 时间片分配 181 4.5.4 进程调度时机 182 4.6 进程切换过程分析 183 4.6.1 选取合适进程 183 4.6.2 完成上下文切换 184 4.7 空闲进程的初始化 187 4.7.1 空闲进程的内核态栈 187 4.7.2 空闲进程的内存描述符 188 4.7.3 空闲进程的硬件上下文 190 4.7.4 空闲进程的任务状态段 190 第5章 中断和异常 192 5.1 基础知识 193 5.1.1 中断和异常的定义 193 5.1.2 中断和异常的分类 193 5.1.3 中断和异常的对比 194 5.2 处理机制 195 5.2.1 IA32架构下的处理机制 195 5.2.2 Linu
共计8个压缩包 本压缩包是:part08.rar (哈哈终于全上传完了) 出版社:人民邮电出版社 ·页码:368 页 ·出版日期:2008年 ·ISBN:7115187118/9787115187116 ·条形码:9787115187116 ·包装版本:1版 ·装帧:平装 ·开本:16 ·中文:中文 ·附带品描述:附光盘一张 ·市场价格:49元 内容简介 Linux内核是Linux操作系统中最核心的部分,用于实现对硬件部件的编程控制和接口操作。《Linux2.6内核标准教程》深入、系统地讲解了 Linux内核的工作原理,对Linux内核的核心组件逐一进行深入讲解。 全书共8章,首先讲解Linux系统的引导过程;然后对Linux内核的3大核心模块——内存管理、进程管理、中断和异常处理进行了深入的分析; 在此基础上,对时间度量、系统调用进行了分析和讨论;最后讲解了Linux内核中常见的同步机制,使读者掌握每处理器变量和RCU这两种新的 同步机制。 《Linux2.6内核标准教程》适合Linux内核爱好者、Linux驱动开发人员、Linux系统工程师参考使用,也可以作为计算机及相关专业学生深入学 习操作系统的参考书。 引用: 目录 第1章 Linux内核学习基础 1 1.1 为什么研究Linux内核 2 1.1.1 Linux的历史来源 2 1.1.2 Linux的发展现状 3 1.1.3 Linux的前景展望 3 1.2 选择什么版本进行研究 3 1.3 内核基本结构 4 1.3.1 内核在操作系统中的地位 4 1.3.2 Linux 2.6内核源代码目录树简介 5 1.3.3 Linux 2.6内核的新特性 8 1.4 如何阅读本书 9 1.4.1 内核探索工具 10 1.4.2 推荐阅读方法 12 第2章 引导过程分析 14 2.1 内核镜像的构建过程 15 2.1.1 编译内核的步骤及分析 15 2.1.2 内核镜像构建过程分析 16 2.2 系统引导过程分析 18 2.2.1 傀儡引导扇区 18 2.2.2 探测系统资源 21 2.2.3 解压内核镜像 35 2.2.4 进入保护模式 40 2.2.5 系统最终初始化 47 2.3 系统引导过程总结 47 第3章 内存管理 50 3.1 基础知识 51 3.1.1 存储器地址 51 3.1.2 分段机制 52 3.1.3 分页机制 59 3.2 内核页表的初始化过程 65 3.2.1 启用分页机制 65 3.2.2 构建内核页表 68 3.3 物理内存的描述方法 76 3.3.1 内存节点 77 3.3.2 内存区域 81 3.3.3 物理页框 85 3.4 物理内存的初始化过程 86 3.4.1 探测系统物理内存 87 3.4.2 初始化内存分配器 89 3.5 物理内存的分配与回收 101 3.5.1 伙伴分配算法 101 3.5.2 对象缓冲技术 103 3.6 内核地址空间 105 3.6.1 常规映射地址空间 105 3.6.2 固定映射地址空间 107 3.6.3 长久内核映射空间 109 3.6.4 临时内核映射空间 116 3.6.5 非连续映射地址空间 119 第4章 进程管理 128 4.1 进程与线程的概念 129 4.1.1 程序与进程 129 4.1.2 进程与线程 129 4.2 进程描述符 131 4.2.1 进程标识符 132 4.2.2 进程的状态 132 4.2.3 进程上下文 134 4.2.4 当前进程 139 4.3 进程的组织形式 143 4.3.1 进程标识符构成的哈希表 143 4.3.2 所有进程构成的双向链表 148 4.3.3 执行态进程组成的运行队列 149 4.3.4 阻塞态进程组成的等待队列 152 4.4 进程的创建过程 155 4.4.1 进程创建的接口函数 156 4.4.2 进程创建的处理过程 162 4.5 进程调度算法 177 4.5.1 进程的分类 178 4.5.2 进程优先级 178 4.5.3 时间片分配 181 4.5.4 进程调度时机 182 4.6 进程切换过程分析 183 4.6.1 选取合适进程 183 4.6.2 完成上下文切换 184 4.7 空闲进程的初始化 187 4.7.1 空闲进程的内核态栈 187 4.7.2 空闲进程的内存描述符 188 4.7.3 空闲进程的硬件上下文 190 4.7.4 空闲进程的任务状态段 190 第5章 中断和异常 192 5.1 基础知识 193 5.1.1 中断和异常的定义 193 5.1.2 中断和异常的分类 193 5.1.3 中断和异常的对比 194 5.2 处理机制 195 5.2.1 IA32架构下的处理机制 195
共计8个压缩包 本压缩包是:part01.rar 出版社:人民邮电出版社 ·页码:368 页 ·出版日期:2008年 ·ISBN:7115187118/9787115187116 ·条形码:9787115187116 ·包装版本:1版 ·装帧:平装 ·开本:16 ·中文:中文 ·附带品描述:附光盘一张 ·市场价格:49元 内容简介 Linux内核是Linux操作系统中最核心的部分,用于实现对硬件部件的编程控制和接口操作。《Linux2.6内核标准教程》深入、系统地讲解了 Linux内核的工作原理,对Linux内核的核心组件逐一进行深入讲解。 全书共8章,首先讲解Linux系统的引导过程;然后对Linux内核的3大核心模块——内存管理、进程管理、中断和异常处理进行了深入的分析; 在此基础上,对时间度量、系统调用进行了分析和讨论;最后讲解了Linux内核中常见的同步机制,使读者掌握每处理器变量和RCU这两种新的 同步机制。 《Linux2.6内核标准教程》适合Linux内核爱好者、Linux驱动开发人员、Linux系统工程师参考使用,也可以作为计算机及相关专业学生深入学 习操作系统的参考书。 引用: 目录 第1章 Linux内核学习基础 1 1.1 为什么研究Linux内核 2 1.1.1 Linux的历史来源 2 1.1.2 Linux的发展现状 3 1.1.3 Linux的前景展望 3 1.2 选择什么版本进行研究 3 1.3 内核基本结构 4 1.3.1 内核在操作系统中的地位 4 1.3.2 Linux 2.6内核源代码目录树简介 5 1.3.3 Linux 2.6内核的新特性 8 1.4 如何阅读本书 9 1.4.1 内核探索工具 10 1.4.2 推荐阅读方法 12 第2章 引导过程分析 14 2.1 内核镜像的构建过程 15 2.1.1 编译内核的步骤及分析 15 2.1.2 内核镜像构建过程分析 16 2.2 系统引导过程分析 18 2.2.1 傀儡引导扇区 18 2.2.2 探测系统资源 21 2.2.3 解压内核镜像 35 2.2.4 进入保护模式 40 2.2.5 系统最终初始化 47 2.3 系统引导过程总结 47 第3章 内存管理 50 3.1 基础知识 51 3.1.1 存储器地址 51 3.1.2 分段机制 52 3.1.3 分页机制 59 3.2 内核页表的初始化过程 65 3.2.1 启用分页机制 65 3.2.2 构建内核页表 68 3.3 物理内存的描述方法 76 3.3.1 内存节点 77 3.3.2 内存区域 81 3.3.3 物理页框 85 3.4 物理内存的初始化过程 86 3.4.1 探测系统物理内存 87 3.4.2 初始化内存分配器 89 3.5 物理内存的分配与回收 101 3.5.1 伙伴分配算法 101 3.5.2 对象缓冲技术 103 3.6 内核地址空间 105 3.6.1 常规映射地址空间 105 3.6.2 固定映射地址空间 107 3.6.3 长久内核映射空间 109 3.6.4 临时内核映射空间 116 3.6.5 非连续映射地址空间 119 第4章 进程管理 128 4.1 进程与线程的概念 129 4.1.1 程序与进程 129 4.1.2 进程与线程 129 4.2 进程描述符 131 4.2.1 进程标识符 132 4.2.2 进程的状态 132 4.2.3 进程上下文 134 4.2.4 当前进程 139 4.3 进程的组织形式 143 4.3.1 进程标识符构成的哈希表 143 4.3.2 所有进程构成的双向链表 148 4.3.3 执行态进程组成的运行队列 149 4.3.4 阻塞态进程组成的等待队列 152 4.4 进程的创建过程 155 4.4.1 进程创建的接口函数 156 4.4.2 进程创建的处理过程 162 4.5 进程调度算法 177 4.5.1 进程的分类 178 4.5.2 进程优先级 178 4.5.3 时间片分配 181 4.5.4 进程调度时机 182 4.6 进程切换过程分析 183 4.6.1 选取合适进程 183 4.6.2 完成上下文切换 184 4.7 空闲进程的初始化 187 4.7.1 空闲进程的内核态栈 187 4.7.2 空闲进程的内存描述符 188 4.7.3 空闲进程的硬件上下文 190 4.7.4 空闲进程的任务状态段 190 第5章 中断和异常 192 5.1 基础知识 193 5.1.1 中断和异常的定义 193 5.1.2 中断和异常的分类 193 5.1.3 中断和异常的对比 194 5.2 处理机制 195 5.2.1 IA32架构下的处理机制 195 5.2.2 Linu
以下是一个简单的Linux字符设备驱动程序模板,供参考: ```c #include <linux/module.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/device.h> #include <linux/uaccess.h> #define DEVICE_NAME "mychardev" #define CLASS_NAME "mycharclass" static int major_num = 0; static struct class* mycharclass = NULL; static struct device* mychardev = NULL; static struct cdev mycdev; static int mychardev_open(struct inode*, struct file*); static int mychardev_release(struct inode*, struct file*); static ssize_t mychardev_read(struct file*, char*, size_t, loff_t*); static ssize_t mychardev_write(struct file*, const char*, size_t, loff_t*); static struct file_operations mychardev_fops = { .owner = THIS_MODULE, .open = mychardev_open, .release = mychardev_release, .read = mychardev_read, .write = mychardev_write, }; static int __init mychardev_init(void) { // allocate major number dynamically if (alloc_chrdev_region(&major_num, 0, 1, DEVICE_NAME) < 0) { return -1; } // create device class if ((mycharclass = class_create(THIS_MODULE, CLASS_NAME)) == NULL) { unregister_chrdev_region(major_num, 1); return -1; } // create device if ((mychardev = device_create(mycharclass, NULL, major_num, NULL, DEVICE_NAME)) == NULL) { class_destroy(mycharclass); unregister_chrdev_region(major_num, 1); return -1; } // initialize cdev cdev_init(&mycdev, &mychardev_fops); mycdev.owner = THIS_MODULE; // add cdev to kernel if (cdev_add(&mycdev, major_num, 1) < 0) { device_destroy(mycharclass, major_num); class_destroy(mycharclass); unregister_chrdev_region(major_num, 1); return -1; } printk(KERN_INFO "mychardev: registered\n"); return 0; } static void __exit mychardev_exit(void) { cdev_del(&mycdev); device_destroy(mycharclass, major_num); class_destroy(mycharclass); unregister_chrdev_region(major_num, 1); printk(KERN_INFO "mychardev: unregistered\n"); } static int mychardev_open(struct inode* inodep, struct file* filep) { printk(KERN_INFO "mychardev: opened\n"); return 0; } static int mychardev_release(struct inode* inodep, struct file* filep) { printk(KERN_INFO "mychardev: closed\n"); return 0; } static ssize_t mychardev_read(struct file* filep, char* buffer, size_t len, loff_t* offset) { printk(KERN_INFO "mychardev: read from device\n"); return 0; } static ssize_t mychardev_write(struct file* filep, const char* buffer, size_t len, loff_t* offset) { printk(KERN_INFO "mychardev: wrote to device\n"); return len; } module_init(mychardev_init); module_exit(mychardev_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("A simple character device driver"); ``` 需要注意的是,该模板仅提供了一个最基本的字符设备驱动程序框架,需要根据实际需求进行修改。此外,还需要在Makefile中添加相应的编译规则,将驱动程序编译成内核模块。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值