Linux下SPI设备驱动实验:向SPI驱动框架中加入字符设备驱动框架代码

一.  简介

前一篇文章编写了SPI设备驱动框架代码,文章如下:

Linux下SPI设备驱动实验:SPI设备驱动框架编写-CSDN博客

本文继续SPI驱动代码的编写。向SPI驱动框架中加入字符设备驱动框架代码。

二.  向SPI驱动框架中加入字符设备驱动框架代码

1.  添加字符设备驱动框架的代码

打开 ubuntu系统,通过 vscode 打开18_spi 工程。向SPI设备驱动框架中添加字符设备驱动框架的代码。添加如下:

(1)  字符设备注册的一套流程,放在 spi_driver的 probe函数中。

(2)  字符设备注销的一套流程,放在 spi_driver的 remove函数中。

添加字符设备驱动框架的代码后,spi_icm20608.c文件中代码如下:

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/of.h>
#include <linux/spi/spi.h>
#include <linux/delay.h>#define  ICM20608_NAME   "icm20608"
#define  ICM20608_CNT    1//设备结构体
struct icm20608_Dev{dev_t devid;  //设备号int major;     //主设备号int minor;     //次设备号 struct cdev led_cdev; struct class * class;   //类(自动创建设备节点用)struct device * device; //设备(自动创建设备节点用) 
};struct icm20608_Dev icm20608_dev;/*打开设字符备函数 */
static int icm20608_open(struct inode *inode, struct file *filp)
{printk("icm20608_open\n");return 0;
}/*读字符设备中数据的函数*/
ssize_t icm20608_read(struct file * filp, char __user * buf, size_t count, loff_t * ppos)
{int ret = 0;printk("icm20608_read!\n");return ret;
}/*关闭设备函数*/
int icm20608_release(struct inode * inode, struct file * filp)
{printk("led_release\n");return 0;
}//字符设备的函数集
const struct file_operations fops = {  .owner = THIS_MODULE,.open = icm20608_open,.read = icm20608_read,.release = icm20608_release,
};static int icm20608_probe(struct spi_device* spi_dev)
{int ret = 0;printk("icm20608_probe!\n");//设备号的分配icm20608_dev.major = 0;if(icm20608_dev.major) //给定主设备号{icm20608_dev.devid = MKDEV(icm20608_dev.major, 0);ret = register_chrdev_region(icm20608_dev.devid, ICM20608_CNT, ICM20608_NAME);}else{ //没有给定主设备号ret = alloc_chrdev_region(&(icm20608_dev.devid), 0, ICM20608_CNT, ICM20608_NAME);	icm20608_dev.major = MAJOR(icm20608_dev.devid);icm20608_dev.minor = MINOR(icm20608_dev.devid);}printk("dev.major: %d\n", icm20608_dev.major);printk("dev.minor: %d\n", icm20608_dev.minor);if (ret < 0) {printk("register-chrdev failed!\n");goto fail_devid;}//初始化设备icm20608_dev.led_cdev.owner = THIS_MODULE;cdev_init(&icm20608_dev.led_cdev, &fops);//注册设备ret = cdev_add(&icm20608_dev.led_cdev, icm20608_dev.devid, ICM20608_CNT);if(ret < 0){printk("cdev_add failed!\r\n");goto fail_adddev;}/* 3.自动创建设备节点 *///创建类icm20608_dev.class = class_create(THIS_MODULE, ICM20608_NAME); if (IS_ERR(icm20608_dev.class)) {ret = PTR_ERR(icm20608_dev.class);goto fail_class;}   //创建设备icm20608_dev.device = device_create(icm20608_dev.class, NULL, icm20608_dev.devid, NULL, ICM20608_NAME);if (IS_ERR(icm20608_dev.device)) {ret = PTR_ERR(icm20608_dev.device);goto fail_dev_create;}  return 0;fail_dev_create:class_destroy(icm20608_dev.class);
fail_class:cdev_del(&icm20608_dev.led_cdev);
fail_adddev:unregister_chrdev_region(icm20608_dev.devid, ICM20608_CNT);
fail_devid:return ret;
}static int icm20608_remove(struct spi_device* spi_dev)
{printk("icm20608_remove!\n");/*注销字符设备*///1. 删除设备cdev_del(&icm20608_dev.led_cdev);//2. 注销设备号unregister_chrdev_region(icm20608_dev.devid, ICM20608_CNT);/*摧毁类与设备(自动创建设备节点时用) *///3. 摧毁设备device_destroy(icm20608_dev.class, icm20608_dev.devid);//4. 摧毁类class_destroy(icm20608_dev.class);return 0;
}//传统驱动与设备匹配方法
static struct spi_device_id spi_device_id_table[] = {{ "icm20608", 0},{ }
};//设备树匹配方法
static struct of_device_id of_device_table[] = {{ .compatible = "alientek,icm20608" },  //必须与设备树中设备节点compatible值一致{ }
};/*SPI驱动结构体*/
struct spi_driver icm20608_driver = {.driver = {.name = "icm20608",.owner = THIS_MODULE,.of_match_table = of_match_ptr(of_device_table),},.id_table = spi_device_id_table,.probe = icm20608_probe,.remove = icm20608_remove,
};/*模块加载 */
static int __init icm20608_init(void)
{return spi_register_driver(&icm20608_driver);
}/*模块卸载 */
static void __exit icm20608_exit(void)
{spi_unregister_driver(&icm20608_driver);
}/*驱动加载与卸载 */
module_init(icm20608_init);
module_exit(icm20608_exit);
MODULE_LICENSE("GPL"); //模块 Licence
MODULE_AUTHOR("WeiWuXian"); //作者

2.  编译驱动模块

对以上的驱动代码进行模块化编译:

wangtian@wangtian-virtual-machine:~/zhengdian_Linux/Linux_Drivers/18_spi$ make
make -C /home/wangtian/zhengdian_Linux/linux/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga M=/home/wangtian/zhengdian_Linux/Linux_Drivers/18_spi modules
make[1]: 进入目录“/home/wangtian/zhengdian_Linux/linux/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga”CC [M]  /home/wangtian/zhengdian_Linux/Linux_Drivers/18_spi/spi_icm20608.oBuilding modules, stage 2.MODPOST 1 modulesCC      /home/wangtian/zhengdian_Linux/Linux_Drivers/18_spi/spi_icm20608.mod.oLD [M]  /home/wangtian/zhengdian_Linux/Linux_Drivers/18_spi/spi_icm20608.ko
make[1]: 离开目录“/home/wangtian/zhengdian_Linux/linux/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga”

可以看出,驱动模块正常编译通过。

三. 编写应用程序(测试程序) 

在 18_spi工程目录下,创建应用程序 icm20608_app.c文件。icm20608_app.c文件代码实现如下:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>/*
* 打开/关闭 Led灯
* 参数:
* ./icm20608_app /dev/icm20608 
*/
int main(int argc, char* argv[])
{int fd = 0,ret = 0;char * device_name = NULL;unsigned short data[3] = {0};if(argc != 2){printf("main's param number error!\n");return -1;}device_name = argv[1];fd = open(device_name, O_RDWR);if(fd < 0){printf("open led device failed!\n");return -1;}ret = read(fd, data, sizeof(data));close(fd);return 0;
}

终端进入 18_spi工程的根目录下,输入如下命令编译应用程序:

arm-linux-gnueabihf-gcc icm20608_app.c -o icm20608_app

这里可以编译通过。生成 icm20608_app。

接下来通过运行应用程序,对驱动模块进行测试,确定是否会正常运行到 open函数,read函数,release函数。

测试方法以及确认SPI驱动是否运行正常,可以参考如下文章:

I2C驱动实验:测试I2C驱动框架代码-CSDN博客

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Cesium中实现镜头光晕

镜头光晕 镜头光晕 (Lens Flares) 是模拟相机镜头内的折射光线的效果&#xff0c;主要作用就是让太阳光/其他光源更加真实&#xff0c;和为您的场景多增添一些气氛。 Cesium 中实现 其实 Cesium 里面也是有实现一个镜头光晕效果的&#xff0c;添加方式如下&#xff0c;只是效…

Python教学入门:数字类型与字符串

字符串元素组成的序列 字符串元素组成的序列指的是字符串中的每个字符按照一定的顺序排列形成的序列。在 Python 中&#xff0c;字符串是由字符组成的有序序列&#xff08;Sequence&#xff09;&#xff0c;每个字符在字符串中有其固定的位置&#xff08;索引&#xff09;&…

Android RecyclerView的LayoutManager配置

RecyclerView的item布局方式依赖于其配置的布局管理器。不同的布局管理器可以实现不同的界面效果。 LayoutManager介绍 RecyclerView可以通过setLayoutManager设置布局管理器&#xff0c;该方法的源码如下&#xff1a; /*** Set the {link LayoutManager} that this RecyclerV…

java网络编程 BufferedReader的readLine方法读不到数据且一直阻塞

最近在整理Java IO相关内容&#xff0c;会遇到一些以前没有注意的问题&#xff0c;特此记录&#xff0c;以供自查和交流。 需求&#xff1a; 基于Java的BIO API&#xff0c;实现简单的客户端和服务端通信模型&#xff0c;客户端使用BufferedReader的readLine方法读取System.i…

7、docker 集群

docker集群 1、docker file参数设置 2、docker composeCompose和Docker兼容性常用参数Docker-compose.yml配置文件Docker-compose命令大全compose常用调试命令compose文件格式示例应用python flask-rediscpu和gpu配置 附件参考&#xff1a; 1、docker file 参考&#xff1a;ht…

ASPICE 追溯性实践分享

01前言 接着之前的分享&#xff0c;遗留的追溯性ASPICE 认证实践及个人理解分享-CSDN博客文章浏览阅读961次&#xff0c;点赞22次&#xff0c;收藏17次。ASPICE是Automotive 和SPICE的组合&#xff0c;全英文为&#xff08;Automotive Software ProcessImprovement and Determ…

树的遍历算法题总结(第二十六天)

144. 二叉树的前序遍历 题目 给你二叉树的根节点 root &#xff0c;返回它节点值的 前序 遍历。 答案 class Solution {List<Integer> res new ArrayList(); public List<Integer> preorderTraversal(TreeNode root) {deal(root);return res;}void deal(TreeN…

C++修炼之路之继承<二>

目录 一&#xff1a;子类的六大默认成员函数 二&#xff1a;继承与友元 三&#xff1a;继承与静态成员 四&#xff1a;复杂的继承关系菱形继承菱形虚拟继承 1.单继承 2.多继承 3.菱形继承&#xff1b;一种特殊的多继承 4.菱形虚拟继承 5.虚拟继承解决数据冗余和二…

华为OD-C卷-内存冷热标记[100分]C++-100%

题目描述 现代计算机系统中通常存在多级的存储设备,针对海量 workload 的优化的一种思路是将热点内存页优先放到快速存储层级,这就需要对内存页进行冷热标记。 一种典型的方案是基于内存页的访问频次进行标记,如果统计窗口内访问次数大于等于设定阈值,则认为是热内存页,…

小程序 前端如何用wx.request获取 access_token接口调用凭据

在微信小程序中,获取access_token通常是通过wx.request方法来实现的。以下是一个简单的示例代码: 1.获取小程序的appID 与 secret(小程序密钥) 登录之后,请点击左侧的"开发管理"==>点击"开发设置" 就可以找到 2. 在javascript 中的代码: // 定…

【大模型完全入门手册】——大模型入门理论(基于Transformer的预训练语言模型)

博主作为一名大模型开发算法工程师,很希望能够将所学到的以及实践中感悟到的内容梳理成为书籍。作为先导,以专栏的形式先整理内容,后续进行不断更新完善。希望能够构建起从理论到实践的全流程体系。 助力更多的人了解大模型,接触大模型,一起感受AI的魅力! Transformer架构…

性能优化工具

CPU 优化的各类工具 network netperf 服务端&#xff1a; $ netserver Starting netserver with host IN(6)ADDR_ANY port 12865 and family AF_UNSPEC$ cat netperf.sh #!/bin/bash count$1 for ((i1;i<count;i)) doecho "Instance:$i-------"# 下方命令可以…

Rust 语言使用 SQLite 数据库

SQLite 是一种广泛使用的轻量级数据库&#xff0c;它通过简单的文件来承载数据&#xff0c;无需复杂的服务器配置。正因如此&#xff0c;它成为了许多桌面和移动应用的首选数据库。在 Rust 生态中&#xff0c;rusqlite 库为开发者提供了操作 SQLite 数据库的简洁且有效的方法。…

如何用Redis高效实现12306的复杂售票业务

12306的售票业务是一个复杂的系统&#xff0c;需要考虑高并发、高可用、数据一致性等问题。使用Redis作为缓存和持久化存储&#xff0c;可以提高系统的性能和可扩展性&#xff0c;以下是一些可能的实现方式&#xff1a; 1 票源信息缓存&#xff1a;将票源信息&#xff08;如车次…

算法刷题记录2

4.图 4.1.被围绕的区域 思路&#xff1a;图中只有与边界上联通的O才不算是被X包围。因此本题就是从边界上的O开始递归&#xff0c;找与边界O联通的O&#xff0c;并标记为#&#xff08;代表已遍历&#xff09;&#xff0c;最后图中剩下的O就是&#xff1a;被X包围的O。图中所有…

SQC、SQA

QC 品质控制/质量控制&#xff08;QC即英文Quality Control的简称&#xff0c;中文意义是品质控制&#xff09;其在ISO8402&#xff1a;1994的定义是“为达到品质要求所采取的作业技术和活动”。有些推行ISO9000的组织会设置这样一个部门或岗位&#xff0c;负责ISO9000标准所要…

Spring Boot 中 Controller 接口参数注解全攻略与实战案例详解

引言 在 Spring Boot 应用程序中&#xff0c;Controller 是 MVC 架构模式中的核心组件之一&#xff0c;负责处理 HTTP 请求并返回响应结果。为了更好地映射请求、解析请求参数、执行业务逻辑和生成视图或 JSON 数据&#xff0c;Controller 中广泛使用了各种注解。本文将全面梳…

温湿度传感器(DHT11)以及光照强度传感器(BH1750)的使用

前言 对于一些单片机类的环境检测或者智能家居小项目中&#xff0c;温湿度传感器&#xff08;DHT11&#xff09;以及光照强度传感器&#xff08;BH1750&#xff09;往往是必不可少的两个外设&#xff0c;下面我们来剖析这两个外设的原理&#xff0c;以及使用。 1. 温湿度传感…

C语言中,__attribute__关键字

在C语言中&#xff0c;__attribute__是一种特殊的关键字&#xff0c;用于提供关于变量、函数或类型的附加信息。这些信息可以用于编译器优化、代码检查或其他目的。 以下是一些常见的C语言attribute及其用法&#xff1a; 1. __attribute__((const))&#xff1a;表示一个变量的…

Prometheus指标

文章目录 Prometheus指标主要参数解释一、可用性监测(0代表存在异常或未启动,1代表运行中)二、节点监测三、服务监测1.HDFS监测2.Yarn监测3.Hive监测4.Kafka监测5.Zookeeper监测Prometheus指标 主要参数解释 # 节点IP和端口(instance) 例如:192.168.1.226:9100、192.168.1.…