当前位置: 首页 > news >正文

搭建论坛网站百度账号

搭建论坛网站,百度账号,建设区服务网站,网络维护工资多少一个月Linux驱动开发野火实战(一):LED控制驱动详解 文章目录 Linux驱动开发野火实战(一):LED控制驱动详解引言一、基础知识1.1 什么是字符设备驱动1.2 重要的数据结构read 函数write 函数open 函数release 函数 二…

Linux驱动开发野火实战(一):LED控制驱动详解


文章目录

  • Linux驱动开发野火实战(一):LED控制驱动详解
  • 引言
  • 一、基础知识
    • 1.1 什么是字符设备驱动
    • 1.2 重要的数据结构
      • read 函数
      • write 函数
      • open 函数
      • release 函数
  • 二、 驱动程序实现
    • 2.1 完整的驱动代码示例
    • 2.2 整体流程(图解)
    • 2.3 用户空间与内核空间交互(图解)
    • 2.4 驱动模块初始化
      • 虚拟地址映射
    • 2.5 拷贝数据
    • 2.6 控制GPIO输出的LED开关状态
    • 2.7 LED驱动程序的退出函数
  • 三、实验过程
    • 项目编译
    • 连接开发板
      • 挂载NFS文件系统
    • 加载驱动(点灯!)
  • 总结


引言

在Linux设备驱动开发中,字符设备驱动是最基础也是最常见的驱动类型。本文将从理论到实践,详细讲解字符设备驱动的开发流程,帮助读者掌握驱动开发的核心知识


一、基础知识

1.1 什么是字符设备驱动

字符设备(Character Device)是Linux中最基本的设备类型之一,它的特点是数据以字符流的方式被访问,像串口、键盘、LED等都属于字符设备。与块设备不同,字符设备不能随机访问,只能顺序读写。

1.2 重要的数据结构

在开发字符设备驱动之前,我们需要了解几个关键的数据结构:

struct file_operations {struct module *owner;ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);int (*open) (struct inode *, struct file *);int (*release) (struct inode *, struct file *);...
};

这个结构体定义了驱动程序需要实现的接口函数。

read 函数

static ssize_t led_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)

作用: 响应用户空间的读取请求
参数:

  • filp:文件结构体指针
  • buf:用户空间缓冲区指针
  • cnt:要读取的字节数
  • offt:文件位置指针
    返回值:
  • 成功返回实际读取的字节数
  • 失败返回负错误码
  • 使用场景:
  • 读取设备状态
  • 获取设备数据
  • 将数据从内核空间复制到用户空间

write 函数

static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)

作用: 响应用户空间的写入请求
参数:

  • filp:文件结构体指针
  • buf:用户空间数据缓冲区指针
  • cnt:要写入的字节数
  • offt:文件位置指针
    返回值:
  • 成功返回实际写入的字节数
  • 失败返回负错误码
    使用场景:
  • 向设备发送控制命令
  • 更新设备状态
  • 将数据从用户空间复制到内核空间

open 函数

static int led_open(struct inode *inode, struct file *filp)

作用: 当用户空间调用 open() 打开设备文件时被调用
参数:

  • inode:包含文件系统信息的结构体,如设备号等
  • filp:文件结构体,包含文件操作方法、私有数据等
    返回值:
  • 成功返回0
  • 失败返回负错误码
    使用场景:
  • 初始化设备
  • 检查设备状态
  • 分配资源
  • 增加使用计数

release 函数

static int led_release(struct inode *inode, struct file *filp)

作用: 当最后一个打开的文件被关闭时调用
参数:

  • inode:索引节点结构体指针
  • filp:文件结构体指针
    返回值:
  • 成功返回0
  • 失败返回负错误码
    使用场景:
  • 释放资源
  • 清理设备状态
  • 减少使用计数

二、 驱动程序实现

2.1 完整的驱动代码示例

代码如下:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>#include <linux/fs.h>
#include <linux/uaccess.h>
#include <asm/io.h>#define DEV_MAJOR 0		   /* 动态申请主设备号 */
#define DEV_NAME "red_led" /*led设备名字 *//* GPIO虚拟地址指针 */
static void __iomem *IMX6U_CCM_CCGR1;
static void __iomem *SW_MUX_GPIO1_IO04;
static void __iomem *SW_PAD_GPIO1_IO04;
static void __iomem *GPIO1_DR;
static void __iomem *GPIO1_GDIR;static int led_open(struct inode *inode, struct file *filp)
{return 0;
}static ssize_t led_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{return -EFAULT;
}static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{unsigned char databuf[10];if (cnt > 10)cnt = 10;/*从用户空间拷贝数据到内核空间*/if (copy_from_user(databuf, buf, cnt)){return -EIO;}if (!memcmp(databuf, "on", 2)){iowrite32(0 << 4, GPIO1_DR);}else if (!memcmp(databuf, "off", 3)){iowrite32(1 << 4, GPIO1_DR);}/*写成功后,返回写入的字数*/return cnt;
}static int led_release(struct inode *inode, struct file *filp)
{return 0;
}/* 自定义led的file_operations 接口*/
static struct file_operations led_fops = {.owner = THIS_MODULE,.open = led_open,.read = led_read,.write = led_write,.release = led_release,
};int major = 0;
static int __init led_init(void)
{/* GPIO相关寄存器映射 */IMX6U_CCM_CCGR1 = ioremap(0x20c406c, 4);SW_MUX_GPIO1_IO04 = ioremap(0x20e006c, 4);SW_PAD_GPIO1_IO04 = ioremap(0x20e02f8, 4);GPIO1_GDIR = ioremap(0x0209c004, 4);GPIO1_DR = ioremap(0x0209c000, 4);/* 使能GPIO1时钟 */iowrite32(0xffffffff, IMX6U_CCM_CCGR1);/* 设置GPIO1_IO04复用为普通GPIO*/iowrite32(5, SW_MUX_GPIO1_IO04);/*设置GPIO属性*/iowrite32(0x10B0, SW_PAD_GPIO1_IO04);/* 设置GPIO1_IO04为输出功能 */iowrite32(1 << 4, GPIO1_GDIR);/* LED输出高电平 */iowrite32(1 << 4, GPIO1_DR);/* 注册字符设备驱动 */major = register_chrdev(DEV_MAJOR, DEV_NAME, &led_fops);printk(KERN_ALERT "led major:%d\n", major);return 0;
}static void __exit led_exit(void)
{/* 取消映射 */iounmap(IMX6U_CCM_CCGR1);iounmap(SW_MUX_GPIO1_IO04);iounmap(SW_PAD_GPIO1_IO04);iounmap(GPIO1_DR);iounmap(GPIO1_GDIR);/* 注销字符设备驱动 */unregister_chrdev(major, DEV_NAME);
}module_init(led_init);
module_exit(led_exit);MODULE_LICENSE("GPL2");
MODULE_AUTHOR("embedfire ");
MODULE_DESCRIPTION("led_module");
MODULE_ALIAS("led_module");

2.2 整体流程(图解)

在这里插入图片描述

2.3 用户空间与内核空间交互(图解)

在这里插入图片描述

2.4 驱动模块初始化

虚拟地址映射

  1. ioremap 函数
void __iomem *ioremap(unsigned long phys_addr, unsigned long size);

作用: 将物理地址映射到虚拟地址空间
参数:

  • phys_addr:物理地址
  • size:映射的大小(字节数)
    返回值: 映射后的虚拟地址指针
  • void * 类型的指针,指向被映射的虚拟地址
  • __iomem 主要是用于编译器的检查地址在内核空间的有效性
    为什么要用: Linux内核出于安全考虑,不允许直接访问物理地址,必须先映射到虚拟地址

GPIO相关寄存器映射

	IMX6U_CCM_CCGR1 = ioremap(0x20c406c, 4);SW_MUX_GPIO1_IO04 = ioremap(0x20e006c, 4);SW_PAD_GPIO1_IO04 = ioremap(0x20e02f8, 4);GPIO1_GDIR = ioremap(0x0209c004, 4);GPIO1_DR = ioremap(0x0209c000, 4);
  1. 虚拟地址读写
void iowrite32(u32 b, void __iomem *addr)   //写入一个双字(32bit)unsigned int ioread32(void __iomem *addr)   //读取一个双字(32bit)
/* 使能GPIO1时钟 */iowrite32(0xffffffff, IMX6U_CCM_CCGR1);/* 设置GPIO1_IO04复用为普通GPIO*/iowrite32(5, SW_MUX_GPIO1_IO04);/*设置GPIO属性*/iowrite32(0x10B0, SW_PAD_GPIO1_IO04);/* 设置GPIO1_IO04为输出功能 */iowrite32(1 << 4, GPIO1_GDIR);/* LED输出高电平 */iowrite32(1 << 4, GPIO1_DR);
  1. register_chrdev 函数
int register_chrdev(unsigned int major, const char *name, const struct file_operations *fops);

作用: 注册字符设备驱动
参数:

major:主设备号(0表示动态分配)
name:设备名称
fops:文件操作结构体
次设备号为0,次设备号数量为256
返回值: 成功返回主设备号,失败返回负值
为什么要用: 向Linux系统注册一个字符设备,使系统能够识别和管理该设备

在这里插入图片描述

2.5 拷贝数据

copy_from_user函数

unsigned long copy_from_user(void *to, const void __user *from, unsigned long n);

作用: 将数据从用户空间复制到内核空间
参数:

  • to:内核空间目标地址
  • from:用户空间源地址
  • n:复制的字节数
    返回值: 成功返回0,失败返回未复制的字节数
    为什么要用: 内核空间和用户空间是隔离的,需要专门的函数来安全地传输数据,要是有野指针会导致整个系统的崩溃,所以是起到一个安全的作用。

2.6 控制GPIO输出的LED开关状态

if (!memcmp(databuf, "on", 2))  // 比较是否接收到"on"命令
{iowrite32(0 << 4, GPIO1_DR); // GPIO1_4输出低电平,LED亮
}
else if (!memcmp(databuf, "off", 3)) // 比较是否接收到"off"命令
{iowrite32(1 << 4, GPIO1_DR); // GPIO1_4输出高电平,LED灭
}
  • memcmp()函数:
int memcmp(const void *str1, const void *str2, size_t n)
// 比较两个内存区域的前n个字节
// 返回0表示相等

2.7 LED驱动程序的退出函数

static void __exit led_exit(void)
{// 1. 取消IO内存映射iounmap(IMX6U_CCM_CCGR1);iounmap(SW_MUX_GPIO1_IO04);iounmap(SW_PAD_GPIO1_IO04);iounmap(GPIO1_DR);iounmap(GPIO1_GDIR);// 2. 注销字符设备unregister_chrdev(major, DEV_NAME);
}
  • iounmap 函数
void iounmap(void __iomem *addr);

作用: 解除I/O内存映射
参数:

addr: 要解除映射的虚拟地址
为什么要用: 释放ioremap占用的资源,防止内存泄漏

  • unregister_chrdev 函数
void unregister_chrdev(unsigned int major, const char *name);

作用: 注销字符设备驱动
参数:

major:设备的主设备号
name:设备名称
为什么要用: 在驱动卸载时清理系统资源

三、实验过程

项目编译

在这里插入图片描述
然后make
在这里插入图片描述

连接开发板

打开手机热点并连上
让电脑跟手机在同一个局域网内

  • ubuntu端
    在这里插入图片描述

  • 开发板端
    在这里插入图片描述

挂载NFS文件系统

sudo mount -t nfs ”NFS服务端IP”:/home/embedfire/workdir /mnt

我们ubuntu的IP为192.168.46.118
所以为

sudo mount -t nfs 192.168.46.118:/home/embedfire/workdir /mnt

在这里插入图片描述
挂载成功后进入共享文件夹查看

ubuntu把ko文件复制到共享文件夹中
在这里插入图片描述

我们到共享文件夹ls查看
在这里插入图片描述

加载驱动(点灯!)

在这里插入图片描述
244是设备号(动态分配)
0是次设备号
为什么是0
因为在register_chrdev函数定义了
次设备号在(0~256之间随便选)
ebf-buster-linux/include/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);
}

创建设备文件
在这里插入图片描述
利用echo应用打开灯的命令
在这里插入图片描述
请添加图片描述

利用echo应用关灯的命令
在这里插入图片描述
卸载模块
在这里插入图片描述


总结

本文详细介绍了Linux字符设备驱动的开发流程,包括:

  • 基本概念和原理
  • 完整的代码实现
  • 详细的流程图解
  • 实际操作
    通过本文的学习,大家应该能够掌握字符设备驱动的开发方法,并能够开发简单的字符设备驱动程序。

文章转载自:
http://rumination.c7498.cn
http://paean.c7498.cn
http://disillusionize.c7498.cn
http://unbusinesslike.c7498.cn
http://babouche.c7498.cn
http://hyposulfurous.c7498.cn
http://adaptor.c7498.cn
http://polydrug.c7498.cn
http://homeomorphous.c7498.cn
http://concretize.c7498.cn
http://rectorial.c7498.cn
http://pori.c7498.cn
http://predicatively.c7498.cn
http://autoionization.c7498.cn
http://overbodice.c7498.cn
http://theodicy.c7498.cn
http://econometric.c7498.cn
http://keratogenous.c7498.cn
http://anonyma.c7498.cn
http://alta.c7498.cn
http://schoolroom.c7498.cn
http://putrid.c7498.cn
http://sacahuiste.c7498.cn
http://samurai.c7498.cn
http://rouille.c7498.cn
http://berserk.c7498.cn
http://uvulotomy.c7498.cn
http://bitcasting.c7498.cn
http://hyperacid.c7498.cn
http://cookery.c7498.cn
http://druse.c7498.cn
http://lithy.c7498.cn
http://viva.c7498.cn
http://retain.c7498.cn
http://plankton.c7498.cn
http://changeability.c7498.cn
http://haifa.c7498.cn
http://pseudosophistication.c7498.cn
http://reelingly.c7498.cn
http://cajun.c7498.cn
http://ventricose.c7498.cn
http://unsugared.c7498.cn
http://ops.c7498.cn
http://photoxylography.c7498.cn
http://megavolt.c7498.cn
http://entame.c7498.cn
http://cryogenic.c7498.cn
http://haida.c7498.cn
http://rhinopolypus.c7498.cn
http://titular.c7498.cn
http://plow.c7498.cn
http://arnold.c7498.cn
http://flagon.c7498.cn
http://filipina.c7498.cn
http://glossina.c7498.cn
http://nagaoka.c7498.cn
http://oophorectomy.c7498.cn
http://miseducation.c7498.cn
http://ecospecies.c7498.cn
http://repairable.c7498.cn
http://cha.c7498.cn
http://snicket.c7498.cn
http://pneumogastric.c7498.cn
http://sided.c7498.cn
http://cauda.c7498.cn
http://punctated.c7498.cn
http://ulsterite.c7498.cn
http://neimenggu.c7498.cn
http://encaustic.c7498.cn
http://smokery.c7498.cn
http://straightlaced.c7498.cn
http://sorn.c7498.cn
http://muscle.c7498.cn
http://poetically.c7498.cn
http://unsplinterable.c7498.cn
http://enos.c7498.cn
http://nuj.c7498.cn
http://sitrep.c7498.cn
http://nationalism.c7498.cn
http://buddhistical.c7498.cn
http://duumvirate.c7498.cn
http://enamel.c7498.cn
http://umber.c7498.cn
http://poc.c7498.cn
http://flaxbush.c7498.cn
http://parastatal.c7498.cn
http://mensal.c7498.cn
http://unvaryingly.c7498.cn
http://ramee.c7498.cn
http://unclimbable.c7498.cn
http://cocopan.c7498.cn
http://unequalize.c7498.cn
http://sudoriparous.c7498.cn
http://sauropod.c7498.cn
http://galvanic.c7498.cn
http://virustatic.c7498.cn
http://anadyr.c7498.cn
http://educe.c7498.cn
http://vdi.c7498.cn
http://woollen.c7498.cn
http://www.zhongyajixie.com/news/77360.html

相关文章:

  • 做自媒体需要哪些网站在线代理浏览网页
  • 我的世界做视频封面的网站推广网
  • 快速网站开发seo是什么意思 seo是什么职位
  • php网站开发价格朔州seo
  • 网站规划书500字长春网站优化指导
  • 国内外优秀建筑设计网站广州引流推广公司
  • 昌平手机网站建设湖南seo网站开发
  • 简洁大方的网站模板google网站入口
  • 网站建设服务合同模板下载全渠道营销的概念
  • 品牌营销咨询机构青岛seo结算
  • 网站域名所有权证明dw网站制作
  • 妈妈网站源码网络互联网推广
  • 做网站赤峰短网址生成器免费
  • 阿里巴巴怎么建设网站首页百度一下官方网页版
  • ps中怎样做网站轮播图片华与华营销策划公司
  • 番禺区网站建设公司西安seo网站推广优化
  • 高端的科技网站建设常州网络推广平台
  • 池州做网站肇庆网站建设制作
  • 做局域网站数据库seo关键词使用
  • 公司注销后网站备案吗东莞seo网站推广建设
  • 打开百度网站咨询公司
  • 贵阳网站优化公司营销运营主要做什么
  • 医院网站建设模板下载优化大师官方免费下载
  • 甘肃省城乡建设网站排名优化公司哪家靠谱
  • b2b网站有哪些盈利模式互联网项目
  • 没被屏蔽的国外新闻网站网站关键词优化报价
  • 深圳建站推广公司集团网站推广
  • 重庆专业网站搭建公司steam交易链接在哪
  • 哈尔滨网站制作公司哪家好株洲最新今日头条
  • 可信的大连网站建设徐州百度运营中心