文章目录

  • 前言
  • 1、分离设计
    • 驱动程序分析---程序分层
      • 通用驱动程序---面向对象
      • 个性化驱动程序---分离
    • APP 程序分析

前言

韦东山嵌入式Linux驱动开发基础知识学习笔记
文章中大多内容来自韦东山老师的文档,还有部分个人根据自己需求补充的内容
视频教程地址:https://www.bilibili.com/video/BV14f4y1Q7ti

上一章在驱动中引入面向对象和分层的设计思想
在驱动里简单来说面向对象就是抽象一个结构体作为设备的类,然后将结构体成员作为对象
而分层设计思想简单来说就是将 内核相关的操作和硬件强相关操作分离 达到内核相关操作通用,硬件相关操作个性化目的
本节将介绍分离思想
【嵌入式Linux】嵌入式Linux驱动开发基础知识之LED驱动框架–面向对象、分层设计思想

1、分离设计

▲面向对象、分层、分离思想体现

将使能、操作GPIO的流程抽象成统一的接口,LED的init可以去调用这些接口,其中添加struct led_resource结构体,其中保存了LED需要的资源即GPIO的group & pin,实现初始化。一系列操作相当于封装了GPIO的寄存器相关操作供设备使用

驱动程序分析—程序分层

通用驱动程序—面向对象

led_opr.h:包含led设备结构体类

#ifndef _LED_OPR_H
#define _LED_OPR_Hstruct led_operations {int (*init) (int which); /* 初始化LED, which-哪个LED */       int (*ctl) (int which, char status); /* 控制LED, which-哪个LED, status:1-亮,0-灭 */int (*exit) (void);
};struct led_operations *get_board_led_opr(void);#endif

leddrv.c:给APP提供接口

#include <linux/module.h>#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>#include "led_opr.h"#define LED_NUM 2/* 1. 确定主设备号                                                                 */
static int major = 0;
static struct class *led_class;
struct led_operations *p_led_opr;#define MIN(a, b) (a < b ? a : b)/* 3. 实现对应的open/read/write等函数,填入file_operations结构体                   */
static ssize_t led_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);return 0;
}/* write(fd, &val, 1); */
static ssize_t led_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
{int err;char status;struct inode *inode = file_inode(file);int minor = iminor(inode);printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);err = copy_from_user(&status, buf, 1);/* 根据次设备号和status控制LED */p_led_opr->ctl(minor, status);return 1;
}static int led_drv_open (struct inode *node, struct file *file)
{int minor = iminor(node);printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);/* 根据次设备号初始化LED */p_led_opr->init(minor);return 0;
}static int led_drv_close (struct inode *node, struct file *file)
{printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);return 0;
}/* 2. 定义自己的file_operations结构体                                              */
static struct file_operations led_drv = {.owner     = THIS_MODULE,.open    = led_drv_open,.read    = led_drv_read,.write   = led_drv_write,.release = led_drv_close,
};/* 4. 把file_operations结构体告诉内核:注册驱动程序                                */
/* 5. 谁来注册驱动程序啊?得有一个入口函数:安装驱动程序时,就会去调用这个入口函数 */
static int __init led_init(void)
{int err;int i;printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);major = register_chrdev(0, "100ask_led", &led_drv);  /* /dev/led */led_class = class_create(THIS_MODULE, "100ask_led_class");err = PTR_ERR(led_class);if (IS_ERR(led_class)) {printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);unregister_chrdev(major, "led");return -1;}for (i = 0; i < LED_NUM; i++)device_create(led_class, NULL, MKDEV(major, i), NULL, "100ask_led%d", i); /* /dev/100ask_led0,1,... */p_led_opr = get_board_led_opr();return 0;
}/* 6. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数           */
static void __exit led_exit(void)
{int i;printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);p_led_opr->exit();for (i = 0; i < LED_NUM; i++)device_destroy(led_class, MKDEV(major, i)); /* /dev/100ask_led0,1,... */device_destroy(led_class, MKDEV(major, 0));class_destroy(led_class);unregister_chrdev(major, "100ask_led");
}/* 7. 其他完善:提供设备信息,自动创建设备节点                                     */module_init(led_init);
module_exit(led_exit);MODULE_LICENSE("GPL");

个性化驱动程序—分离

board_A_led:包含LED所需要的资源信息

#include "led_resource.h"static struct led_resource led_resources = {.num = 2,/* PA10 green */.pin[0] = GROUP_PIN(0,10),/* PG8 yellow */.pin[1] = GROUP_PIN(6,8),
};struct led_resource *get_led_resouce(void)
{return &led_resources;
}

chip_demo_gpio.c:包含GPIO相关操作、使能函数,LED设备对象从这里获得接口

#include <linux/module.h>#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <asm/io.h>#include "led_opr.h"
#include "led_resource.h"/* registers */
// RCC_PLL4CR地址:0x50000000 + 0x894
static volatile unsigned int *RCC_PLL4CR;// RCC_MP_AHB4ENSETR 地址:0x50000000 + 0xA28
static volatile unsigned int *RCC_MP_AHB4ENSETR;// GPIOA_MODER 地址:0x50002000 + 0x00
static volatile unsigned int *GPIOA_MODER;// GPIOA_BSRR 地址: 0x50002000 + 0x18
static volatile unsigned int *GPIOA_BSRR;// GPIOG_MODER 地址:0x50008000 + 0x00
static volatile unsigned int *GPIOG_MODER;// GPIOG_BSRR 地址: 0x50008000 + 0x18
static volatile unsigned int *GPIOG_BSRR;
/* registers end */struct led_resource *led_rsc;static int board_demo_led_init (int which) /* 初始化LED, which-哪个LED */
{if (!led_rsc){led_rsc = get_led_resouce();}/* 寄存器映射到变量 */if (!RCC_PLL4CR){// RCC_PLL4CR地址:0x50000000 + 0x894RCC_PLL4CR = ioremap(0x50000000 + 0x894, 4);// RCC_MP_AHB4ENSETR 地址:0x50000000 + 0xA28RCC_MP_AHB4ENSETR = ioremap(0x50000000 + 0xA28, 4);// GPIOA_MODER 地址:0x50002000 + 0x00GPIOA_MODER = ioremap(0x50002000 + 0x00, 4);// GPIOA_BSRR 地址: 0x50002000 + 0x18GPIOA_BSRR = ioremap(0x50002000 + 0x18, 4);// GPIOG_MODER 地址:0x50008000 + 0x00GPIOG_MODER = ioremap(0x50008000 + 0x00, 4);// GPIOG_BSRR 地址: 0x50008000 + 0x18GPIOG_BSRR = ioremap(0x50008000 + 0x18, 4);}switch(GROUP(led_rsc->pin[which])){case 0:{printk("init pin of group A ...\n");/* enalbe PLL4, it is clock source for all gpio */*RCC_PLL4CR |= (1<<0);while ((*RCC_PLL4CR & (1<<1)) == 0);/* enable gpio */*RCC_MP_AHB4ENSETR |= (1<<GROUP(led_rsc->pin[which]));/** configure gpio as output */*GPIOA_MODER &= ~(3 << (PIN(led_rsc->pin[which])*2) );*GPIOA_MODER |= (1<< (PIN(led_rsc->pin[which])*2) );/* ... */break;}case 6:{printk("init pin of group G ...\n");/* enalbe PLL4, it is clock source for all gpio */*RCC_PLL4CR |= (1<<0);while ((*RCC_PLL4CR & (1<<1)) == 0);/* enable gpio */*RCC_MP_AHB4ENSETR |= (1<<GROUP(led_rsc->pin[which]));/** configure gpg8 as gpio* configure gpio as output */*GPIOG_MODER &= ~((PIN(led_rsc->pin[which])*2));*GPIOG_MODER |= ((PIN(led_rsc->pin[which])*2));break;}default:printk("not support %d\n", led_rsc->pin[which]);}return 0;
}static int board_demo_led_ctl (int which, char status) /* 控制LED, which-哪个LED, status:1-亮,0-灭 */
{//printk("%s %s line %d, led %d, %s\n", __FILE__, __FUNCTION__, __LINE__, which, status ? "on" : "off");printk("set led %s: group %d, pin %d\n", status ? "on" : "off", GROUP(led_rsc->pin[which]), PIN(led_rsc->pin[which]));switch(GROUP(led_rsc->pin[which])){case 0:{printk("set pin of group A ...\n");*GPIOA_BSRR = ( 1<< (16*status + PIN(led_rsc->pin[which])));break;}case 6:{printk("set pin of group G ...\n");*GPIOG_BSRR = ( 1<< (16*status + PIN(led_rsc->pin[which])));break;}default:printk("not support %d\n", led_rsc->pin[which]);}return 0;
}static int board_demo_led_exit (void)
{if(RCC_PLL4CR){iounmap(RCC_PLL4CR);iounmap(RCC_MP_AHB4ENSETR);iounmap(GPIOA_MODER);iounmap(GPIOA_BSRR);iounmap(GPIOG_MODER);iounmap(GPIOG_BSRR);}return 0;
}static struct led_operations board_demo_led_opr = {.init = board_demo_led_init,.ctl  = board_demo_led_ctl,.exit = board_demo_led_exit,
};struct led_operations *get_board_led_opr(void)
{return &board_demo_led_opr;
}

APP 程序分析

ledtest.c


#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>/** ./ledtest /dev/100ask_led0 on* ./ledtest /dev/100ask_led0 off*/
int main(int argc, char **argv)
{int fd;char status;/* 1. 判断参数 */if (argc != 3) {printf("Usage: %s <dev> <on | off>\n", argv[0]);return -1;}/* 2. 打开文件 */fd = open(argv[1], O_RDWR);if (fd == -1){printf("can not open file %s\n", argv[1]);return -1;}/* 3. 写文件 */if (0 == strcmp(argv[2], "on")){status = 1;write(fd, &status, 1);}else{status = 0;write(fd, &status, 1);}close(fd);return 0;
}

【嵌入式Linux】嵌入式Linux驱动开发基础知识之驱动设计的思想:面向对象/分层/分离相关推荐

  1. 【嵌入式Linux】嵌入式Linux驱动开发基础知识之Pinctrl子系统和GPIO子系统的使用

    文章目录 前言 1.Pinctrl子系统 1.1.为什么有Pinctrl子系统 1.2.重要的概念 1.3.代码中怎么引用pinctrl 2.GPIO子系统 2.1.为什么有GPIO子系统 2.2.在 ...

  2. 【嵌入式Linux】嵌入式Linux驱动开发基础知识之按键驱动框架

    文章目录 前言 1.APP怎么读取按键值 1.1.查询方式 1.2.休眠-唤醒方式 1.3.poll方式 1.3.异步通知方式 1.5. 驱动程序提供能力,不提供策略 2.按键驱动程序框架--查询方式 ...

  3. 【嵌入式Linux】嵌入式Linux驱动开发基础知识之LED模板驱动程序的改造:设备树

    文章目录 前言 1.驱动的三种编写方法 2.怎么使用设备树写驱动程序 2.1.设备树节点要与platform_driver能匹配 2.2.修改platform_driver的源码 3.实验和调试技巧 ...

  4. 【嵌入式Linux】嵌入式Linux驱动开发基础知识之设备树模型

    文章目录 前言 1.设备树的作用 2.设备树的语法 2.1.设备树的逻辑图和dts文件.dtb文件 2.1.1.1Devicetree格式 1DTS文件的格式 node的格式 properties的格 ...

  5. 【嵌入式Linux】嵌入式Linux驱动开发基础知识之总线设备驱动模型

    文章目录 前言 1.驱动编写的三种方法 1.1.传统写法 1.2.总线驱动模型 1.3.设备树驱动模型 2.Linux实现分离:Bus/Dev/Drv模型 2.1.Bus/Dev/Drv模型 2.2. ...

  6. 【嵌入式Linux】嵌入式Linux驱动开发基础知识之LED驱动框架--面向对象、分层设计思想

    文章目录 前言 1.LED驱动程序框架 1.1.对于LED驱动,我们想要什么样的接口? 1.2.LED驱动要怎么写,才能支持多个板子?分层写 1.3.程序分析 驱动程序 应用程序 Makefile 1 ...

  7. 【嵌入式Linux】嵌入式Linux驱动开发基础知识之第一个驱动

    文章目录 前言 1.Hello驱动 1.1.APP打开的文件在内核中如何表示? 1.2.打开字符设备节点时,内核中也有对应的struct file 1.3.如何编写驱动程序? 1.4.驱动程序代码 1 ...

  8. linux课程_【课程完结】嵌入式Linux应用/驱动开发基础知识两大篇章已全部录制完毕 共72集...

    完结撒花 <第四篇嵌入式Linux应用开发基础知识> <第五篇嵌入式Linux驱动开发基础知识> 两大篇章已全部录制完毕 共计 72 集 01 嵌入式Linux应用开发基础知识 ...

  9. 驱动开发基础知识必修-(一)嵌入式开发板的启动过程

    驱动开发必修-嵌入式开发板的启动过程 简介 从打印日志入手 熟悉启动过程 1.执行u-boot程序 2.加载linux内核 3.挂载rootfs 4.加载完后 进入终端(命令输入行) UBOOT 1. ...

最新文章

  1. 2020 AI产业图谱启动,勾勒中国AI技术与行业生态
  2. Unrecognised tag: #39;encoding#39; (position: START_TAG seen ...lt;/versiongt;\r\n\t\t\t\tlt;en...
  3. 成功解决torch\cuda\__init__.py“, line 208, in check_error raise Cuda Error(res) torch.cuda.Cuda Error: C
  4. 【Linux网络编程】并发服务器之多进程模型
  5. css中的换行符_如何使用CSS防止项目列表中的换行符?
  6. Spring Boot 2.3.3 正式发布!
  7. JDBC最基本CRUD操作工具类
  8. python sql逐行读取数据库数据,使用python读取数据库中的内容 把爬虫爬到的内容,存储在mysql数据库中...
  9. 指针和const限定
  10. web:网站性能工具Yslow
  11. php 字符串加,php字符串如何增加
  12. Bartender 让Mac选项列不再拥挤
  13. Azure 网站上的 Java
  14. Java 最长递增子序列_最长递增子序列问题 Java
  15. [速记] 网络安全复习——选择题汇总
  16. OKR:目标要定性,关键结果要定量
  17. java开发中/final关键字/多态/抽象类/接口/形式参数与返回值/内部类/匿名内部类知识梳理
  18. MATLAB实现三角剖分(Delaunay)算法
  19. 电脑Svchost.exe 进程占CPU100% 的解决办法
  20. android五大布局的作用,Android五大布局与实际应用详解

热门文章

  1. 使用计算机六年级,二十年后的电子计算机六年级作文
  2. java调用MySQL脚本_Java调用SQL脚本执行常用的方法示例
  3. mac html编辑器 免费,Mac下 10 款最棒的编辑器
  4. pytorch使用masked掩盖某些值(筛选值)
  5. python selenium使用JS新建标签(new tab)与切换标签
  6. java爬虫爬取主流房屋网站
  7. 因为计算机中丢失ssce5432.dll,ssce5432.dll 64位
  8. java代码审查工具_APP开发常用的一些工具包、软件工具
  9. python做前端mongodb_Python爬虫之mongodb和python交互
  10. 洛谷P1494 [国家集训队]小Z的袜子