字符设备驱动基础篇4——字符设备驱动读写接口的操作实践
以下内容源于朱有鹏嵌入式课程的学习,如有侵权,请告知删除。
参考资料:http://www.cnblogs.com/biaohc/p/6575074.html。
一、细节
1、自动分配主设备号
- 注册函数传参时,第一个参数填0,表示让内核自动分配主设备号,返回值为主设备号。注销时,注销刚才返回的主设备号。
2、设备文件的创建
- 设备文件的关键信息是:设备号 = 主设备号 + 次设备号,使用ls -l去查看设备文件,就可以得到设备文件对应的主次设备号。
- 使用“mknod /dev/xxx c 主设备号 次设备号”来创建设备文件,其中xxx表示设备文件名,c表示字符设备;
- xxx不能用vim来打开,可以用ls /dev/xxx -l查看。
二、读写接口的操作实践
(1)应用(用户空间)和驱动(内核空间)之间的数据交换
- copy_from_user,将数据从用户空间复制到内核空间;
- copy_to_user,将数据从内核空间;
- copy_from_user:如果成功复制则返回0,如果不成功复制则返回尚未成功复制的剩下的字节数;
- 复制机制、mmap的映射两者比较:复制时内核空间和用户空间的地址不一样,效率低。
(2)代码
应用层代码app.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
//这是应用层#define FILE "/dev/test" // 刚才手工mknod创建的设备文件名,问题是mknod需要输入主设备号,和自动获取不背离吗?char buf[100];int main(void)
{int fd = -1;fd = open(FILE, O_RDWR);//这里的open,对应的是驱动文件中的.open指定的函数if (fd < 0){printf("open %s error.\n", FILE);return -1;}printf("open %s success..\n", FILE);// 读写文件write(fd, "helloworld2222", 14);read(fd, buf, 100);printf("读出来的内容是:%s.\n", buf);// 关闭文件close(fd);return 0;
}
驱动文件module_test.c
#include <linux/module.h> // module_init module_exit
#include <linux/init.h> // __init __exit
#include <linux/fs.h>
#include <asm/uaccess.h>#define MYNAME "testchar"int mymajor; //内核自动分配的主设备号
char kbuf[100]; //内核空间(即驱动空间,毕竟内核和驱动属于同一层)的bufstatic int test_chrdev_open(struct inode *inode, struct file *file)
{// 这个函数中真正应该放置的是打开这个设备的硬件操作代码部分// 但是现在暂时我们写不了这么多,所以用一个printk打印个信息来做代表。printk(KERN_INFO "test_chrdev_open\n");return 0;
}static int test_chrdev_release(struct inode *inode, struct file *file)
{printk(KERN_INFO "test_chrdev_release\n");return 0;
}//读函数,即从内核空间(驱动空间)读取数据到用户空间
ssize_t test_chrdev_read(struct file *file, char __user *ubuf, size_t count, loff_t *ppos)
{int ret = -1;printk(KERN_INFO "test_chrdev_read\n");//将内容从内核空间(驱动空间)读取到用户空间//返回值为0说明读取成功,读取不成功时返回值是剩余没有读取的字节数ret = copy_to_user(ubuf, kbuf, count);if (ret){printk(KERN_ERR "copy_to_user fail\n");return -EINVAL;}printk(KERN_INFO "copy_to_user success..\n");return 0;
}// 写函数
//1、将应用层的数据先复制到内核中
//2、然后将之以正确的方式写入硬件完成操作。
static ssize_t test_chrdev_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos)
{ //此函数前三个参数,对应应用层的write函数的三个参数?int ret = -1;printk(KERN_INFO "test_chrdev_write\n");// 1、使用该函数将应用层传过来的ubuf中的内容拷贝到驱动空间中的一个buf中//memcpy(kbuf, ubuf); // 不行,因为用户空间和内核空间,两者不在一个地址空间中ret = copy_from_user(kbuf, ubuf, count);if (ret){printk(KERN_ERR "copy_from_user fail\n");return -EINVAL;}printk(KERN_INFO "copy_from_user success..\n");// 2、真正的驱动中,数据从应用层复制到驱动中后,我们就要根据这个数据//去写硬件完成硬件的操作。所以这下面就应该是操作硬件的代码return 0;
}// 自定义一个file_operations结构体变量,并且去填充
static const struct file_operations test_fops = {.owner = THIS_MODULE, // 惯例,直接写即可.open = test_chrdev_open, // 将来应用open打开这个设备时实际调用的就是这个.open对应的函数.release = test_chrdev_release, .write = test_chrdev_write,.read = test_chrdev_read,
};// 模块安装函数
static int __init chrdev_init(void)
{ printk(KERN_INFO "chrdev_init helloworld init\n");// 在module_init宏调用的函数中去注册字符设备驱动// major传0进去表示要让内核帮我们自动分配一个合适的空白的没被使用的主设备号// 内核如果成功分配就会返回分配的主设备好;如果分配失败会返回负数mymajor = register_chrdev(0, MYNAME, &test_fops);if (mymajor < 0){printk(KERN_ERR "register_chrdev fail\n");return -EINVAL;}printk(KERN_INFO "register_chrdev success... mymajor = %d.\n", mymajor);return 0;
}// 模块载函数
static void __exit chrdev_exit(void)
{printk(KERN_INFO "chrdev_exit helloworld exit\n");// 在module_exit宏调用的函数中去注销字符设备驱动unregister_chrdev(mymajor, MYNAME);}module_init(chrdev_init);
module_exit(chrdev_exit);// MODULE_xxx这种宏作用是用来添加模块描述信息
MODULE_LICENSE("GPL"); // 描述模块的许可证
MODULE_AUTHOR("aston"); // 描述模块的作者
MODULE_DESCRIPTION("module test"); // 描述模块的介绍信息
MODULE_ALIAS("alias xxx"); // 描述模块的别名信息
字符设备驱动基础篇4——字符设备驱动读写接口的操作实践相关推荐
- 字符设备驱动基础篇3——字符设备驱动工作原理
以下内容源于朱有鹏嵌入式课程的学习,如有侵权,请告知删除. 参考资料:http://www.cnblogs.com/biaohc/p/6575074.html. 1.系统整体工作原理 (1)应用层-& ...
- 字符设备驱动基础篇1——简单的驱动源码分析
以下内容源于朱有鹏嵌入式课程的学习,如有侵权,请告知删除. 参考资料:http://www.cnblogs.com/biaohc/p/6575074.html module_test.c代码 #inc ...
- 基础篇010.2 STM32驱动RC522 RFID模块之二:STM32硬件SPI驱动RC522
目录 1. 实验硬件及原理图 1.1 RFID硬件 1.2 硬件原理图 2. 单片机与RFID硬件模块分析 3. 利用STM32CubeMX创建MDK工程 3.1 STM32CubeMX工程创建 3. ...
- 【rtthread设备】第一篇:pin设备
[rtthread设备]系列文章 [rtthread设备]第零篇:IO设备 [rtthread设备]第一篇:pin设备 [rtthread设备]第二篇:rtc设备 [rtthread设备]第三篇:ad ...
- 字符设备驱动基础篇5——驱动如何操控硬件(动静态映射操作LED)
以下内容源于朱有鹏嵌入式课程的学习,,如有侵权,请告知删除. 参考资料:http://www.cnblogs.com/biaohc/p/6575074.html 这里的映射,是指物理地址和虚拟地址的对 ...
- 字符设备驱动基础篇0——驱动开发初体验
以下内容源于朱有鹏嵌入式课程的学习,如有侵权,请告知删除. 参考资料:http://www.cnblogs.com/biaohc/p/6575074.html 1.驱动开发的准备工作 (1)内核源码树 ...
- 字符设备驱动高级篇6——内核提供的读写寄存器接口
以下内容源于朱有鹏<物联网大讲堂>课程的学习整理,如有侵权,请告知删除. 1.前面访问寄存器的方式 通过定义指向寄存器的指针,然后解引用来对寄存器进行操作. (1)行不行?sure! (2 ...
- linux驱动基础开发1——linux 设备驱动基本概念-转
学习linux设备驱动首先我们必须明确以下几个概念,为我们接下来学习linux驱动打下坚实的基础: 应用程序.库.内核.驱动程序的关系 设备类型 设备文件.主设备号与从设备号 驱动程序与应用程序的区别 ...
- 敏捷转型行动笔记:内部敏捷教练培训资料分享——基础篇(夯实精益敏捷思想,掌握相关实践)
本篇是内部敏捷教练培训的第二篇,基础篇,由于内容比较多,本章仅分享部分内容,对于敏捷宣言.敏捷相关原则.Scrum框架有关介绍等内容均不列入. 本篇要点:理解精益思想,理解敏捷思想.价值观.原则及若干 ...
最新文章
- linux存储--inode详解(五)
- Winform中跨窗体设置ZedGraph的属性并刷新曲线图
- [算法笔记] 爬楼梯
- KVM虚拟化笔记(七)------kvm虚拟机VNC的配置
- android搜索框功能实现_巧用 Trie 树,实现搜索引擎关键词提示功能
- ZZULIOJ 1098: 复合函数求值(函数专题)
- 关于quick-cocos2d-x
- 【flink】Flink 1.12.2 源码浅析 :Task数据输出
- python第一课教案_Python学习第一课
- elementui如何在input 框中搜索_【挑战自学Python编程】第八天:while循环以及input()函数...
- 今天开始学习ADO.NET中的Connection对象(一)--SqlConnection对象连接SQL Server
- PowerDesigner生成PowerBuilder扩展属性~
- 信号与系统 Matlab 实验 画连续离散系统零极点图 分析连续、离散系统的频率特性 幅频特性曲线 相频特性曲线
- 萤石云谷歌禁用flash_mac chrome屏蔽flash插件怎么办 mac chrome flash启用方法
- 注册表知识和技巧大全
- NC高级UI工厂笔记
- RK987蓝牙机械键盘win和alt键互换
- 用户画像标签数据存储之Elasticsearch存储
- Python爬虫入门实例四之百度、360搜索关键字提交(可自主输入关键字)
- 原创游戏:血战太平洋1.1(可在Dev-C++上运行)
热门文章
- 潭州课堂25班:Ph201805201 django 项目 第三十九课 后台 文章发布,图片上传到 FastDFS后端实现 七牛云讲解(课堂笔记)...
- 《知易行难》扩展练习
- JavaWeb基础—dbutils的简单入门
- 表单验证的初步实现和省市级联
- 函数传参之商品价格计算—JS学习笔记2015-6-6(第50天)
- 从零开始学android开发-布局中 layout_gravity、gravity、orientation、layout_weight
- textbox 和textera 文本框多行后不能拉伸
- CI框架--加载静态内容
- 猫:君主般的眼神 监视领地。 狗
- 使用el-checkbox实现全选,点击失效没有反应