fmql之字符驱动设备(1)

上一篇文章,记录了模块入口和出口函数的编写。

这一篇要继续编写字符驱动程序了。

仍然参考正点原子:

第3.3讲 我的第一个Linux驱动-字符设备驱动框架搭建实验_哔哩哔哩_bilibili

驱动注册和卸载

字符驱动设备的注册函数位register_chrdev

                         卸载函数为unregister_chrdev

linux/fs.h        :

static inline int register_chrdev(unsigned int major, const char *name,const struct file_operations *fops)
{return __register_chrdev(major, 0, 256, name, fops);
}static inline void unregister_chrdev(unsigned int major, const char *name)
{__unregister_chrdev(major, 0, 256, name);
}

目前的代码:

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>#define CHRDEVBASE_MAJOR    200        //主设备号
#define CHRDEVBASE_NAME     "chrdevbase"    //设备名称static int __init chrdevbase_init(void)
{int major;printk(KERN_EMERG "chrdevbase_init\r\n");/*character device: register*/major = register_chrdev(CHRDEVBASE_MAJOR,CHEDEVBASE_NAME,&chrdevbase_fops);return 0;
}/*module exit*/
static void __exit chrdevbase_exit(void)
{printk(KERN_EMERG "chrdevbase_exit\r\n");/*character device: unregister*/unregister_chrdev(CHRDEVBASE_MAJOR,CHEDEVBASE_NAME);
}/* 驱动模块入口和出口函数注册 */
module_init(chrdevbase_init);
module_exit(chrdevbase_exit);MODULE_AUTHOR("Skylar <skylar@33.com>");
MODULE_DESCRIPTION("FMQL Chrdevbase Driver");
MODULE_LICENSE("GPL");

命令cat /proc/devices 可以查看当前已使用的设备号,主设备号不能重复。

设备号

dev_t为无符号32位(u32),包括主设备号(高12位)和次设备号(低20位)

/linux/kdev_t.h        :

#define MINORBITS	20
#define MINORMASK	((1U << MINORBITS) - 1)#define MAJOR(dev)	((unsigned int) ((dev) >> MINORBITS))
#define MINOR(dev)	((unsigned int) ((dev) & MINORMASK))
#define MKDEV(ma,mi)	(((ma) << MINORBITS) | (mi))#define print_dev_t(buffer, dev)					\sprintf((buffer), "%u:%u\n", MAJOR(dev), MINOR(dev))

MAJOR与MINOR宏定义可以获取dev的主/次设备号,MKDEV可以把主/次设备号拼接成一个设备。

file_operations结构体

file_operations结构体为设备的操作函数的集合。添加需要的操作即可。

参考gpio.c的写法(其他文件都可):

static const struct file_operations gpio_fops = {.owner          = THIS_MODULE,.poll           = gpio_poll,.unlocked_ioctl = gpio_ioctl,.write          = gpio_write,.open           = gpio_open,.release        = gpio_release,.llseek		= noop_llseek,
};

.owner是必须写的,照着写就行。

open和release函数是成对出现;write和read也是。

因此,添加以下代码:

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

 之后,给出上述四个函数的定义:(继续参考)

#include <linux/fs.h>static int chrdevbase_open(struct inode *inode, struct file *filp)
{printk("chrdevbase_open\r\n");return 0;
}static int chrdevbase_release(struct inode *inode, struct file *filp)
{printk("chrdevbase_release\r\n");return 0;
}static ssize_t chrdevbase_write(struct file *file, const char __user *buf,size_t count, loff_t *off)
{printk("chrdevbase_write\r\n");return 0;
}static ssize_t chrdevbase_read(struct file *file, char __user *buf, size_t count,loff_t *offset)
{printk("chrdevbase_read\r\n");return 0;
}

makefile编译,生成可执行文件。

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
/***************************************************************
Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.
文件名    : chrdevbase.c
作者      : 正点原子
版本      : V1.0
描述      : chrdevbase驱动文件。
其他      : 无
论坛      : www.openedv.com
日志      : 初版V1.0 2019/1/30 左忠凯创建
修改      :v3.0     2023/6/8  正点原子
***************************************************************/#define CHRDEVBASE_MAJOR    200                     // 主设备号
#define CHRDEVBASE_NAME     "chrdevbase"            // 设备名static char readbuf[100];                           // 读缓冲区
static char writebuf[100];                          // 写缓冲区
static char kerneldata[] = {"kernel data!"};/** @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;
}/** @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;
}/** 设备操作函数结构体*/
static struct file_operations chrdevbase_fops = {.owner = THIS_MODULE,.open = chrdevbase_open,.read = chrdevbase_read,.write = chrdevbase_write,.release = chrdevbase_release,
};/** @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_init(chrdevbase_init);
module_exit(chrdevbase_exit);/** LICENSE和作者信息*/
MODULE_LICENSE("GPL");
MODULE_AUTHOR("alientek");

 

测试APP

 APP.c为Linux应用开发的程序。

 比如,想查看open函数如何调用:

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
/***************************************************************
Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.
文件名     : chrdevbaseApp.c
作者       : 正点原子
版本       : V1.0
描述       : chrdevbase驱测试APP。
其他       : 使用方法:./chrdevbaseApp /dev/chrdevbase <1>|<2>argv[2] 1:读文件argv[2] 2:写文件
论坛       : www.openedv.com
日志 : 初版 V1.0 2019/1/30 正点原子创建
修改 :     V3.0 2023/6/8  正点原子
***************************************************************/static char usrdata[] = {"usr data!"};/** @description     : main主程序* @param - argc    : argv数组元素个数* @param - argv    : 具体参数* @return          : 0 成功;其他 失败*/
int main(int argc, char *argv[])
{int fd, retvalue;char *filename;char readbuf[100], writebuf[100];if(argc != 3){printf("Error Usage!\r\n");return -1;}filename = argv[1];/* 打开驱动文件 */fd  = open(filename, O_RDWR);if(fd < 0){printf("Can't open file %s\r\n", filename);return -1;}if(atoi(argv[2]) == 1){ /* 从驱动文件读取数据 */retvalue = read(fd, readbuf, 50);if(retvalue < 0){printf("read file %s failed!\r\n", filename);}else{/* 读取成功,打印出读取成功的数据 */printf("read data:%s\r\n",readbuf);}}if(atoi(argv[2]) == 2){/* 向设备驱动写数据 */memcpy(writebuf, usrdata, sizeof(usrdata));retvalue = write(fd, writebuf, 50);if(retvalue < 0){printf("write file %s failed!\r\n", filename);}}/* 关闭设备 */retvalue = close(fd);if(retvalue < 0){printf("Can't close file %s\r\n", filename);return -1;}return 0;
}

open函数返回的是文件描述符。

write函数:将userdata传给驱动程序;

read函数:将kerneldata传给

编译APP.c        :

以下内容也可参考:

韦东山嵌入式入门笔记之——应用开发基础篇(三)_韦东山 c应用开发-CSDN博客

韦东山嵌入式入门笔记之——应用开发基础篇(四)_framebuffer 应用编程视频-CSDN博客

韦东山嵌入式入门笔记之——开发板上的第一个APP和驱动程序_韦东山 程序自动运行-CSDN博客

手动添加设备

  1. 执行chrdevbase.ko                lsmod检查一下
  2. 输入命令:mknod /dev/chedevbase c 200 0       创建设备节点

c:字符设备

200:主设备号

0:次设备号

        检查一下        ls /dev/chrdevbase -l

  1.  执行APP:./chedevbaseAPP /dev/chrdevbase 1(或2)

 

FATAL: Module xxx.ko not found in directory /lib/modules/4.1.15-2.1.0+ Modprobe无法装载模块问题_modules no found in directory-CSDN博客

修改modprobe命令:

 but APP运行还是不行:

Linux下-bash: Permission denied 或者 sudo: command not found 错误 - VVingerfly - 博客园 

嵌入式linux运行程序 -sh ./xxx: not found 解决办法_51CTO博客_嵌入式linux应用程序 

 (未完待续。。。)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/147874.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

让PlatformIO支持ESP32C3 SuperMini

先介绍一下这块小尺寸板子&#xff1a; ESP32C3SuperMini是一款基于 Espressif ESP32-C3 WiFi/蓝牙双模芯片的 IoT 迷你开发板。ESP32-C3 是一款32 位 RISC-V CPU&#xff0c;包含FPU&#xff08;浮点单元&#xff09;&#xff0c;可进行32 位单精度运算&#xff0c;具有强大的…

如何写出高收录词的listing文案,先做好这一点

在亚马逊上&#xff0c;关键词是连接买家搜索与产品之间的桥梁&#xff0c;超过80%的购买行为都是通过搜索关键词开始的。因此&#xff0c;文案中包含的精准关键词越多&#xff0c;Listing越能匹配买家的需求&#xff0c;从而提高自然排名并优化广告效果。 亚马逊的收录分为静…

vue.js 展示一个树形结构的数据视图,并禁用其中默认选中的节点

功能描述 展示树形结构&#xff1a; 使用 Element UI 的 <el-tree> 组件展示树形结构数据。数据由 content 数组提供&#xff0c;树形结构包含了嵌套的节点及其子节点。 默认选中节点&#xff1a; 使用 defaultCheckedKeys 属性指定默认选中的节点。这些节点在树形结构渲…

基于51单片机控制恒压供水系统设计

文章目录 前言资料获取设计介绍功能介绍设计程序具体实现截图文档目录设计获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师&#xff0c;一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设…

手把手教您轻松实现微信/QQ/TIM多开,消息防撤回!

文章目录 📖 介绍 📖🏡 环境 🏡📒 防回撤 📒🚀 自动补丁工具(支持多开,支持微信、QQ、TIM)🚀 最新版手动补丁📝 步骤一📝 步骤二⚓️ 相关链接 ⚓️📖 介绍 📖 在日常聊天中,微信消息被撤回的情况屡见不鲜,总让人心中充满好奇——那些被删去的内容…

【c数据结构】OJ练习篇 帮你更深层次理解链表!(相交链表、相交链表、环形链表、环形链表之寻找环形入口点、判断链表是否是回文结构、 随机链表的复制)

目录 一. 相交链表 二. 环形链表 三. 环形链表之寻找环形入口点 四. 判断链表是否是回文结构 五. 随机链表的复制 一. 相交链表 最简单粗暴的思路&#xff0c;遍历两个链表&#xff0c;分别寻找是否有相同的对应的结点。 我们对两个链表的每个对应的节点进行判断比较&…

量化交易----数据透视表----融资融券优惠代码

我们在制定和执行量化策略的过程中&#xff0c;常常需要快速检查目标因子组合的分组下portfolio的超额收益&#xff0c;我们来提供一个快速的方法&#xff0c;可以实现单因子分组&#xff0c;双因子分组和三因子分组 比如拿到一个分析师预测的数据库&#xff0c;和A股市场政策…

python:django项目知识点02——搭建简易授权码核销系统

前言 如标题所述&#xff0c;本篇博客主要围绕快速搭建业务系统展开&#xff0c;旨在&#xff1a;快速、逻辑分明。 适用对象 djangomysql&#xff0c;实现一套授权码核销功能&#xff0c;包含用户登录和授权码核销两个方面内容 业务代码 前述 基础代码已在上篇博客中讲述&…

Vue3:provide-inject实现组件通信

目录 一.作用 1.跨层级通信 2.避免重复声明 3.封装通用服务 二.性质 1.非响应式 2.不可选项 3.高级用法 三.使用 1.爷组件 2.父组件 3.子组件 四.代码 1.爷组件代码 2.父组件代码 3.子组件代码 五.效果 Vue3中的provide-inject机制是用于在组件树中进行依赖注…

01【MATLAB】最小二乘系统辨识

目录 1.系统辨识的定义及其分类 1.1 系统辨识的定义 1.2 系统辨识的分类 2.参数模型 3.系统辨识的步骤 一、最小二乘法&#xff08;Least Squares Method&#xff09;一般步骤 二、LSM原理及应用 三、LSM在控制系统建模中的应用 1.系统辨识的定义及其分类 1.1 系统辨识的…

有没有适合初学者的 OpenLayers 项目实战案例推荐?

对于初学者来说&#xff0c;OpenLayers 提供了一系列实用的项目实战案例&#xff0c;可以帮助你快速上手并掌握关键的开发技能。以下是一些推荐的入门项目案例&#xff1a; 1.基础地图显示&#xff1a; 学习如何创建一个简单的地图视图&#xff0c;并加载基础的地图图层&…

19个邮件群发小技巧,最大水平充分利用邮件营销

邮件群发在现代通信中占据着非常重要的位置。无论是在商业环境还是个人生活中&#xff0c;它都有着广泛的应用。无论您是公司的市场推广专家&#xff0c;还是社交团体的筹办者&#xff0c;掌握有效的邮件群发技巧会帮助您更好地传递信息、节约时间和提升工作效率。 确定目标受众…

DK5V100R20S双引脚同步整流芯片12V 2.4A封装SM-7

高性能双引脚同步整流芯片 DK5V100R20S是一款简单高效率的同步整流芯片&#xff0c;只有A&#xff0c;K两个引脚&#xff0c;分别对应肖特基二极管PN管脚。芯片内部集成了100V功率NMOS管&#xff0c;可以大幅降低二极管导通损耗&#xff0c;提高整机效率&#xff0c;取代或替换…

Debian安装mysql遇到的问题解决及yum源配置

文章目录 一、安装mysql遇到的问题解决二、Debain系统mysql8.0的安装以及远程连接三、彻底卸载软件四、Python 操作 mysql五、debian软件源source.list文件格式说明1. 第一部分2. 第二部分3. 第三部分4. 第四部分5. 关于源的混用问题6. 按需修改自己的sources.list7. 更新软件包…

详解运行时安全检测神器:Falco

在当今快速发展的云计算和容器技术时代,安全已成为组织面临的一大挑战。随着云原生应用的普及,传统的安全措施已不足以应对复杂的分布式环境。在这样的背景下,Falco应运而生,成为云原生安全领域的一颗新星。目前在github中&#xff0c;该项目已经拥有了7.3k的star&#xff0c;众…

显示和隐藏图片【JavaScript】

使用 JavaScript 来实现显示和隐藏图片。下面是一个简单的示例&#xff0c;展示如何通过按钮点击来切换图片的可见性。 实现效果: 代码&#xff1a; <!DOCTYPE html> <html lang"zh"><head><meta charset"UTF-8"><meta name&…

Sample Packing:长序列 LLM 训练的 Attention 问题及优化

一、背景 之前看过部分 Megatron-LM 的源码&#xff0c;也详细分析过对应的 Dataset 和 DataLoader&#xff0c;想当然的认为在 LLM 预训练时会使用 Document Level 的 Mask&#xff0c;也就是常说的 Sample Packing 技术。最近我们在做长序列训练相关工作时发现并非如此&…

灰狼算法求解函数,MATLAB代码

目录 程序说明 概述 主要功能 关键函数 结论 程序说明 概述 该程序实现了灰狼优化算法&#xff08;GWO&#xff09;&#xff0c;用于求解优化问题。该算法模拟灰狼的捕猎行为&#xff0c;通过种群搜索找到最优解。程序中定义了种群数量、问题维度、变量上下界和适应度函…

全行业商家0退货0退款一键卖全球,淘天助力卖家拓展海外生意!

今年7月中旬&#xff0c;淘宝推出了“大服饰全球包邮计划”&#xff0c;在服饰行业先行先试&#xff0c;带领商家拓展海外市场。计划推出以来&#xff0c;吸引了数十万服饰商家报名参与&#xff0c;包括天猫商家蕉下、淘宝商家JOC、美洋等。有服饰商家怀着试一试的心态报了名&a…

碳课堂|CBAM的制度及核心内容

引言 全球变暖和气候变化是21世纪面临的最严峻挑战之一。为应对这一全球性问题&#xff0c;各国纷纷采取措施&#xff0c;减少温室气体排放&#xff0c;并推动可持续发展。其中&#xff0c;欧盟提出的碳边界调整机制&#xff08;CBAM, Carbon Border Adjustment Mechanism&…