IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> arm-linux 字符设备带设备树io操作 -> 正文阅读

[嵌入式]arm-linux 字符设备带设备树io操作

设备树内容如下

?

除了需要/* 设备操作函数 */

还需要 /* 设备结构体 */

eg:

struct dtsled_dev{

? ? dev_t devid; ? ? ? ? ? ?/* 设备号 ? */

? ? struct cdev cdev; ? ? ? /* cdev ? ? */

? ? struct class *class; ? ? ? ?/* 类 ? ? ? ?*/

? ? struct device *device; ?/* 设备 ? ?*/

? ? int major; ? ? ? ? ? ? ?/* 主设备号 ? */

? ? int minor; ? ? ? ? ? ? ?/* 次设备号 ? */

? ? struct device_node ?*nd; /* 设备节点 */

};

初始化注册函数也需要变化

初始化函数需要使用 of_find_node_by_path函数,找到设备树节点:

? ? /* 1、获取设备节点:alphaled */

? ? dtsled.nd = of_find_node_by_path("/alphaled");

初始化函数需要使用 of_find_property函数,找到设备树的兼容性属性

? ? /* 2、获取compatible属性内容 */

? ? proper = of_find_property(dtsled.nd, "compatible", NULL);

/* 3、获取status属性内容 */

? ? ret = of_property_read_string(dtsled.nd, "status", &str);

获取寄存器的内容,很重要!!!

/* 4、获取reg属性内容 */

? ? ret = of_property_read_u32_array(dtsled.nd, "reg", regdata, 10);

需要配置IO映射

IMX6U_CCM_CCGR1 = of_iomap(dtsled.nd, 0);

? ? SW_MUX_GPIO1_IO03 = of_iomap(dtsled.nd, 1);

? ? SW_PAD_GPIO1_IO03 = of_iomap(dtsled.nd, 2);

? ? GPIO1_DR = of_iomap(dtsled.nd, 3);

? ? GPIO1_GDIR = of_iomap(dtsled.nd, 4);

of_iomap
void __iomem *of_iomap(struct device_node *node, int index);

通过设备树的设备结点直接进行设备内存区间的 ioremap(),index是内存段的索引。若设备结点的reg属性有多段,可通过index标示要ioremap的是哪一段,只有1段的情况, index为0。

采用Device Tree后,大量的设备驱动通过of_iomap()进行映射,而不再通过传统的ioremap

引用:https://blog.csdn.net/alimingh/article/details/111666429

在注册驱动使用MKDEV获取主设备号和次设备号

版本:linux-2.6.24.4

宏:

MKDEV(MAJOR, MINOR);??

说明: 获取设备在设备表中的位置。

MAJOR???主设备号

MINOR???次设备号

? ?

内核使用的版本号说明文件:

????在内核?/Documentation?目录下的?devices.txt?有说明。

????一般本地保留的

????????MAJOR

234-239 UNASSIGNED

240-254 char?LOCAL/EXPERIMENTAL USE

240-254 block?LOCAL/EXPERIMENTAL USE??

????????MINOR

1?~?250?(次设备号的?0?不能使用)

??? ?

静态的设备文件建立:

????mknod /dev/gpio_led c 240?

利用register_chrdev_region函数注册

register_chrdev_region() 函数用于分配指定的设备编号范围。如果申请的设备编号范围跨越了主设备号,它会把分配范围内的编号按主设备号分割成较小的子范围,并在每个子范围上调用 __register_chrdev_region() 。如果其中有一次分配失败的话,那会把之前成功分配的都全部退回。

在2.4版本后,内核里就加入了以下几个函数也可以来实现注册字符设备:

分为了静态注册(指定设备编号来注册)、动态分配(不指定设备编号来注册),以及有连续注册的次设备编号范围区间,避免了register_chrdev()浪费资源的缺点? ?

2.1:?

/*指定设备编号来静态注册一个字符设备*/
int register_chrdev_region(dev_t from, unsigned count, const char *name);   

from:?注册的指定起始设备编号,比如:MKDEV(100, 0),表示起始主设备号100, 起始次设备号为0

count:需要连续注册的次设备编号个数,比如: 起始次设备号为0,count=100,表示0~99的次设备号都要绑定在同一个file_operations操作方法结构体上

*name:字符设备名称

当返回值小于0,表示注册失败

2.2:

/*动态分配一个字符设备,注册成功并将分配到的主次设备号放入*dev里*/
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name);

*dev:?存放起始设备编号的指针,当注册成功, *dev就会等于分配到的起始设备编号,可以通过MAJOR()和MINNOR()函数来提取主次设备号

baseminor:次设备号基地址,也就是起始次设备号

count:需要连续注册的次设备编号个数,比如: 起始次设备号(baseminor)为0,baseminor=2,表示0~1的此设备号都要绑定在同一个file_operations操作方法结构体上

*name:字符设备名称

当返回值小于0,表示注册失败

eg:

? ? /* 注册字符设备驱动 */

? ? /* 1、创建设备号 */

? ? if (dtsled.major) { ? ? /* ?定义了设备号 */

? ? ? ? dtsled.devid = MKDEV(dtsled.major, 0);

? ? ? ? register_chrdev_region(dtsled.devid, DTSLED_CNT, DTSLED_NAME);

? ? } else { ? ? ? ? ? ? ? ? ? ? ? ?/* 没有定义设备号 */

? ? ? ? alloc_chrdev_region(&dtsled.devid, 0, DTSLED_CNT, DTSLED_NAME); /* 申请设备号 */

? ? ? ? dtsled.major = MAJOR(dtsled.devid); /* 获取分配号的主设备号 */

? ? ? ? dtsled.minor = MINOR(dtsled.devid); /* 获取分配号的次设备号 */

? ? }

? ? /* 2、初始化cdev */

函数cdev_init()用于初始化一个静态分配的cdev结构体变量,函数cdev_init会自动初始化cdev->ops对象,将函数的第二个输入参数赋值给cdev->ops对象,不会初始化cdev->owner对象,因此在经过函数cdev_alloc()和函数cdev_init()处理之后的cdev结构体变量,在应用程序中只需要给cdev->owner对象赋值,此结构变量就可以被插入Linux内核系统了,作为一个可用的字符设备使用。

? ? dtsled.cdev.owner = THIS_MODULE;

? ? cdev_init(&dtsled.cdev, &dtsled_fops);

#include <linux/cdev.h>

初始化?cdev?后,需要把它添加到系统中去。为此可以调用?cdev_add()函数。传入cdev?结构的指针,起始设备编号,以及设备编号范围。

函数首先将分配的设备号与设备数目保存进cdev结构体中。然后再讲cdev结构体记录在一个 kobj_map 结构的 cdev_map 变量中。

/* 3、添加一个cdev */

? ? cdev_add(&dtsled.cdev, dtsled.devid, DTSLED_CNT);

? ? /* 4、创建类 */

? ? dtsled.class = class_create(THIS_MODULE, DTSLED_NAME);

? ? if (IS_ERR(dtsled.class)) {

? ? ? ? return PTR_ERR(dtsled.class);

? ? }

? ? /* 5、创建设备 */

? ? dtsled.device = device_create(dtsled.class, NULL, dtsled.devid, NULL, DTSLED_NAME);

? ? if (IS_ERR(dtsled.device)) {

? ? ? ? return PTR_ERR(dtsled.device);

? ? }

注销设备驱动

/*

?* @description : 驱动出口函数

?* @param ? ? ? : 无

?* @return ? ? ?: 无

?*/

static void __exit led_exit(void)

{

? ? /* 取消映射 */

? ? iounmap(IMX6U_CCM_CCGR1);

? ? iounmap(SW_MUX_GPIO1_IO03);

? ? iounmap(SW_PAD_GPIO1_IO03);

? ? iounmap(GPIO1_DR);

? ? iounmap(GPIO1_GDIR);

? ? /* 注销字符设备驱动 */

? ? cdev_del(&dtsled.cdev);/* ?删除cdev */

? ? unregister_chrdev_region(dtsled.devid, DTSLED_CNT); /* 注销设备号 */

? ? device_destroy(dtsled.class, dtsled.devid);

? ? class_destroy(dtsled.class);

}

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-06-29 19:16:14  更:2022-06-29 19:16:22 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/29 8:20:08-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计