向新字符设备驱动代码框架中添加Led功能函数

一.  简介

上一篇文章学习编写新字符设备驱动框架代码。文章地址如下:

新字符设备驱动框架代码搭建-CSDN博客

本文在以上这篇文章代码实现的基础上,加入涉及 Led灯的功能函数集实现。

代码实现要求:测试程序(即应用程序)通过设置 Led灯电平的高低,调用到 Led设备驱动程序,从而最终驱动 Led灯的亮灭。

二.  添加Led功能函数

上一篇文章实现了新字符设备驱动代码框架。这里在此基础上加入 Led灯的功能函数的代码。

首先,来完善字符设备Led 的 file_operations结构体,完善后如下:

//字符设备的函数集
const struct file_operations fops = {  .owner = THIS_MODULE,.open = led_open,.write = led_write,.release = led_release,
};

其次,来实现 上面字符设备的 file_operations结构体对应的函数实现。可以参考前面 2_led实验的代码编写,其实代码内容是一样的。

所添加的代码内容包括:file_operations结构体的函数集,Led灯的IO初始化工作。
(1)  添加file_operations结构体的函数操作集

打开 3_newchrled工程, 这里需要添加 file_operations结构体的函数操作集。代码如下:

void led_on_off(unsigned int status)
{unsigned int reg_value = 0;if(LED_ON == status) {reg_value = readl(IMX6ULL_DR);reg_value &= ~(1 << 3);   //bit3清零,低电平,打开Ledwritel(reg_value, IMX6ULL_DR);}else if(LED_OFF == status){reg_value = readl(IMX6ULL_DR);reg_value |= (1 << 3);  //bit3置1,高电平,关闭Ledwritel(reg_value, IMX6ULL_DR);}
}static int newchrled_open(struct inode *inode, struct file *file)
{return 0;
}static ssize_t newchrled_write(struct file * inode, const char __user * buf, size_t count, loff_t * ppos)
{int ret = 0;unsigned char data_buf[1] = {0};ret = copy_from_user(data_buf, buf, count);if(ret < 0){printk("led_write failed!\r\n");return -EFAULT;}led_on_off(data_buf[0]);return 0;
}int newchrled_release(struct inode * inode, struct file * file)
{printk("led_release\r\n");return 0;
}

(2) 添加 Led的IO初始化代码

这里 Led的IO初始化代码,可以添加到 newchrled_init()函数,也就是模块加载接口中;也可以添加到 newchrled_open()函数中,也就是打开设备接口中。

这里我添加到 newchrled_init()接口中,将以下 Led 的IO初始化代码添加到 newchrled_init()接口 中字符设备注册之前:

    unsigned int value = 0;/*Led灯的IO初始化 *///地址映射IMX6ULL_CCM_CCGR1 = ioremap(CCM_CCGR1_BASE, 4);IMX6ULL_SW_MUX_GPIO1_IO03 = ioremap(SW_MUX_GPIO1_IO03_BASE, 4);IMX6ULL_SW_PAD_GPIO01_IO03 = ioremap(SW_PAD_GPIO1_IO03_BASE, 4);IMX6ULL_GDIR = ioremap(GPIO1_GDIR_BASE, 4);IMX6ULL_DR = ioremap(GPIO1_DR_BASE, 4);//使能Led时钟value = readl(IMX6ULL_CCM_CCGR1);value &= ~(3 << 26);value |= (3 << 26); //bit26~27置1writel(value, IMX6ULL_CCM_CCGR1);//复用为GPIO功能writel(0X05, IMX6ULL_SW_MUX_GPIO1_IO03);//配置电气属性writel(0X10B0, IMX6ULL_SW_PAD_GPIO01_IO03);//设置为输出功能value = readl(IMX6ULL_GDIR);value |= (1 << 3);writel(value, IMX6ULL_GDIR);//关闭Led灯(设置为高电平)value = readl(IMX6ULL_DR);value |= (1 << 3);writel(value, IMX6ULL_DR);

三.  整体代码实现

newchrled.c文件中代码如下:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cdev.h>//寄存器的物理地址
#define  CCM_CCGR1_BASE          (0X020C406C)
#define  SW_MUX_GPIO1_IO03_BASE  (0X020E0068)
#define  SW_PAD_GPIO1_IO03_BASE  (0X020E02F4)
#define  GPIO1_GDIR_BASE         (0X0209C004)
#define  GPIO1_DR_BASE           (0X0209C000)//地址映射后寄存器的虚拟地址指针
static void __iomem *  IMX6ULL_CCM_CCGR1;
static void __iomem *  IMX6ULL_SW_MUX_GPIO1_IO03;
static void __iomem *  IMX6ULL_SW_PAD_GPIO01_IO03;
static void __iomem *  IMX6ULL_GDIR;
static void __iomem *  IMX6ULL_DR;#define  NEWCHRLED         "newchrled" //设备名
#define  NEWCHRLED_COUNT   1    //设备个数
#define  LED_OFF           0 //关闭Led灯
#define  LED_ON            1  //打开Led灯//Led设备结构体
struct newchrled_dev{struct cdev led_cdev; dev_t dev_id;  //设备号int major;     //主设备号int minor;     //次设备号 };struct newchrled_dev newchr_led;void led_on_off(unsigned int status)
{unsigned int reg_value = 0;if(LED_ON == status) {reg_value = readl(IMX6ULL_DR);reg_value &= ~(1 << 3);   //bit3清零,低电平,打开Ledwritel(reg_value, IMX6ULL_DR);}else if(LED_OFF == status){reg_value = readl(IMX6ULL_DR);reg_value |= (1 << 3);  //bit3置1,高电平,关闭Ledwritel(reg_value, IMX6ULL_DR);}
}static int newchrled_open(struct inode *inode, struct file *file)
{return 0;
}static ssize_t newchrled_write(struct file * inode, const char __user * buf, size_t count, loff_t * ppos)
{int ret = 0;unsigned char data_buf[1] = {0};ret = copy_from_user(data_buf, buf, count);if(ret < 0){printk("led_write failed!\r\n");return -EFAULT;}led_on_off(data_buf[0]);return 0;
}int newchrled_release(struct inode * inode, struct file * file)
{printk("led_release\r\n");return 0;
}//字符设备的函数集
const struct file_operations fops = {  .owner = THIS_MODULE,.open = newchrled_open,.write = newchrled_write,.release = newchrled_release,
};/*驱动模块入口函数 */
static int __init newchrled_init(void)
{int ret = 0;unsigned int value = 0;printk("newchrled_init!\r\n");/*Led灯的IO初始化 *///地址映射IMX6ULL_CCM_CCGR1 = ioremap(CCM_CCGR1_BASE, 4);IMX6ULL_SW_MUX_GPIO1_IO03 = ioremap(SW_MUX_GPIO1_IO03_BASE, 4);IMX6ULL_SW_PAD_GPIO01_IO03 = ioremap(SW_PAD_GPIO1_IO03_BASE, 4);IMX6ULL_GDIR = ioremap(GPIO1_GDIR_BASE, 4);IMX6ULL_DR = ioremap(GPIO1_DR_BASE, 4);//使能Led时钟value = readl(IMX6ULL_CCM_CCGR1);value &= ~(3 << 26);value |= (3 << 26); //bit26~27置1writel(value, IMX6ULL_CCM_CCGR1);//复用为GPIO功能writel(0X05, IMX6ULL_SW_MUX_GPIO1_IO03);//配置电气属性writel(0X10B0, IMX6ULL_SW_PAD_GPIO01_IO03);//设置为输出功能value = readl(IMX6ULL_GDIR);value |= (1 << 3);writel(value, IMX6ULL_GDIR);//关闭Led灯(设置为高电平)value = readl(IMX6ULL_DR);value |= (1 << 3);writel(value, IMX6ULL_DR);/*注册字符设备 *///设备号的分配if(newchr_led.major) //给定主设备号{newchr_led.dev_id = MKDEV(newchr_led.major, 0);ret = register_chrdev_region(newchr_led.dev_id, NEWCHRLED_COUNT, NEWCHRLED);}else{ //没有给定主设备号ret = alloc_chrdev_region(&(newchr_led.dev_id), 0, NEWCHRLED_COUNT, NEWCHRLED);	newchr_led.major = MAJOR(newchr_led.dev_id);newchr_led.minor = MINOR(newchr_led.dev_id);}if (ret < 0) {printk("register-chrdev failed!\n");return -1;}//初始化设备cdev_init(&newchr_led.led_cdev, &fops);//注册设备cdev_add(&newchr_led.led_cdev, newchr_led.dev_id, NEWCHRLED_COUNT);return 0;
}/*驱动模块出口函数 */
static void __exit newchrled_exit(void)
{printk("newchrled_eixt!\r\n");
/*注销字符设备 *///删除设备cdev_del(&newchr_led.led_cdev);//注销设备号unregister_chrdev_region(newchr_led.dev_id, NEWCHRLED_COUNT);
}/* 注册与卸载驱动设备 */
module_init(newchrled_init);
module_exit(newchrled_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("LingXueWu");

编译驱动代码 3_newchrled,经过编译,可以正常生成 newchrled.ko 驱动文件。下一篇文章对驱动代码进行加载与测试。

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

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

相关文章

【C++】STL 容器 - map 关联容器 ① ( std::map 容器简介 | std::map 容器排序规则 | std::map 容器底层实现 )

文章目录 一、std::map 容器1、std::map 容器简介2、std::map 容器排序规则3、std::map 容器底层实现 二、代码示例 - std::map 容器1、代码示例2、执行结果 一、std::map 容器 1、std::map 容器简介 std::map 容器 是 C 语言 标准模板库 ( STL , Standard Template Library ) …

分布式技术之数据复制技术

文章目录 什么是数据复制技术&#xff1f;数据复制技术原理及应用同步复制技术原理及应用异步复制技术原理及应用半同步复制技术原理及应用三种数据复制技术对比 什么是数据复制技术&#xff1f; 数据复制是一种实现数据备份的技术。数据复制技术&#xff0c;可以保证存储在不…

Plantuml之甘特图语法介绍(二十八)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

基于SpringBoot的在线远程考试系统

文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于SpringBoot的在线远程考试系统,java…

磁盘和文件系统管理

一&#xff1a;磁盘结构&#xff1a; 1.磁盘基础&#xff1a; 扇区固定大小&#xff0c;每个扇区4k。磁盘会进行磨损&#xff0c;损失生命周期。 设备文件&#xff1a; 一切皆文件 设备文件&#xff1a;关联至一个设备驱动程序&#xff0c;进而能够跟与之对应硬件设备进行通…

UDP发送和接受数据

发送数据 public class sendmessage {public static void main (String[] args) throws IOException {DatagramSocket dsnew DatagramSocket();//打包数据开始String s"hello world";byte[] bs.getBytes();//获取InetAddress的对象InetAddress addressInetAddress.g…

什么是IDE?新手用哪个IDE比较

IDE代表集成开发环境&#xff08;Integrated Development Environment&#xff09;&#xff0c;它是一种软件应用程序&#xff0c;提供了一套工具&#xff0c;用于编写、调试和运行软件程序。一个IDE通常包含代码编辑器、编译器、调试器和其他各种工具&#xff0c;以便开发人员…

Rust学习笔记000 安装

安装命令 curl --proto https --tlsv1.2 -sSf https://sh.rustup.rs | sh $ curl --proto https --tlsv1.2 -sSf https://sh.rustup.rs | sh info: downloading installerWelcome to Rust!This will download and install the official compiler for the Rust programming la…

【基础】【Python网络爬虫】【3.chrome 开发者工具】(详细笔记)

Python网络爬虫基础 chrome 开发者工具元素面板&#xff08;Elements)控制台面板&#xff08;Console&#xff09;资源面板&#xff08;Source&#xff09;网络面板&#xff08;Network&#xff09;工具栏Requests Table详情 chrome 开发者工具 ​ 当我们爬取不同的网站是&…

MATLAB常用笔记记录(持续更新)

3.错误使用 reshape 元素数不能更改。请使用 [] 作为大小输入之一&#xff0c;以自动计算该维度的适当大小。 仔细检查之后发现原因是&#xff1a;两个栅格图层的行列数不一致。解决办法如下&#xff1a; 先改变栅格图层1源文件的投影坐标系&#xff0c;再进行掩膜提取&#x…

Linux环境安装2

1 redis单机版安装 1.1 安装 wget http://downloads.sourceforge.net/tcl/tcl8.6.1-src.tar.gz tar -xzvf tcl8.6.1-src.tar.gz cd /usr/local/tcl8.6.1/unix/ ./configure make && make install使用redis-3.2.8.tar.gz&#xff08;截止2017年4月的最新稳定版&…

目标检测YOLO系列从入门到精通技术详解100篇-【目标检测】点云配准

目录 几个相关概念 算法原理 什么是点云 点云的处理 ICP 算法 1 问题描述

常用CSS样式

目录 1、文本超出省略号代替 2、自定义滚动条样式 3、文本无法选中 4、字体间距 5、放大动画效果 6、CSS引用数字字体 7、CSS去角 8、CSS :after、:before、::after、::before的使用 9、CSS使用::after去除浮动 10、时间动画属性 transition 11、颜色渐变 12、解决…

javaWeb学生信息管理系统2

一、学生信息管理系统SIMS 一款基于纯Servlet技术开发的学生信息管理系统&#xff08;SIMS&#xff09;&#xff0c;在设计中没有采用SpringMVC和Spring Boot等框架。系统完全依赖于Servlet来处理HTTP请求和管理学生信息&#xff0c;实现了信息的有效存储、检索和更新&#xf…

React16源码: Component与PureComponent源码实现

概述 Component 就是组件, 这个概念依托于最直观的在react上的一个表现&#xff0c;那就是 React.Component我们写的组件大都是继承于 React.Component 这个baseClass 而写的类这个类代表着我们使用 react 去实现的一个组件那么在react当中不仅仅只有 Component 这一个baseCla…

【web安全】登录界面渗透的思路总结

前言 小菜作者的总结。 如果大家知道其他的安全问题&#xff0c;欢迎大家补充赐教。我们一起完善登录页面的渗透思路。 &#xff08;如果大家有好的博客讲解对应的漏洞&#xff0c;欢迎分享~&#xff09; sql注入 登录页面是需要与数据库打交道的。是需要带入数据库查询的…

JVM之jinfo虚拟机配置信息工具

jinfo虚拟机配置信息工具 1、jinfo jinfo&#xff08;Configuration Info for Java&#xff09;的作用是实时地查看和调整虚拟机的各项参数。 使用jps -v 可以查看虚拟机启动时显示指定的参数列表&#xff0c;但是如果想知道未被显示指定的参数的系统默认值&#xff0c;除 …

GCP 创建1个windows vm 并连接

有时需要临时使用1台windows 的机器 创建windows vm 既然是临时 直接用gcloud command gcloud compute instances create instance-windows \--zoneeurope-west2-c \--machine-typen2d-standard-4 \--boot-disk-size100GB \--image-projectwindows-cloud \--imagewindows-se…

Rust学习笔记001:HELLOW WORLD + Cargo

Rust介绍 Rust&#xff08;中文称为“锈”&#xff09;是一种由Mozilla开发的系统编程语言&#xff0c;它着力于提供安全性、并发性和实用性。Rust的设计目标是消除程序出现的内存安全性问题&#xff0c;如空指针引用、数据竞争等。它通过在编译时进行严格的所有权和借用检查来…

Vue(三):Vue 生命周期与工程化开发

2023 的最后一篇博客&#xff0c;祝大家元旦快乐&#xff0c;新的一年一起共勉&#xff01; 06. Vue 生命周期 6.1 基本介绍 生命周期就是一个 Vue 示例从 创建 到 销毁 的整个过程&#xff0c;创建、挂载、更新、销毁 有一些请求是必须在某个阶段完成之后或者某个阶段之前执行…