| |
|
开发:
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 通过设备树的设备结点直接进行设备内存区间的 ioremap(),index是内存段的索引。若设备结点的reg属性有多段,可通过index标示要ioremap的是哪一段,只有1段的情况, index为0。 采用Device Tree后,大量的设备驱动通过of_iomap()进行映射,而不再通过传统的ioremap 在注册驱动使用MKDEV获取主设备号和次设备号版本:linux-2.6.24.4 宏: MKDEV(MAJOR, MINOR);?? 说明: 获取设备在设备表中的位置。 MAJOR???主设备号 MINOR???次设备号 ? ? 内核使用的版本号说明文件: ????在内核?/Documentation?目录下的?devices.txt?有说明。 ????一般本地保留的 ????????MAJOR234-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会自动初始化 ? ? dtsled.cdev.owner = THIS_MODULE; ? ? cdev_init(&dtsled.cdev, &dtsled_fops);
初始化?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例程四---定时器中断(附工 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
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- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |
数据统计 |