概述

今天看了《韦东山升级版全系列嵌入式视频之总线设备驱动模型》这一节的视频,看完之后感觉有一种似懂非懂的感觉,因此我对改节视频对应源码进行分析,结果如下:

函数关系图

模型分析

该模型分三层:

一、驱动层

二、设备层

三、资源层

数据流向大致为资源层->设备层->驱动层

资源层->设备层

要用到的引脚、设备数量等定义在资源层的resource数组内:

struct resource {

resource_size_t start;

resource_size_t end;

const char *name;

unsigned long flags;

struct resource *parent, *sibling, *child;

};

例:

static struct resource resources[] = {

{

.start = GROUP_PIN(3,1),

.flags = IORESOURCE_IRQ,

.name = "100ask_led_pin",

},

{

.start = GROUP_PIN(5,8),

.flags = IORESOURCE_IRQ,

.name = "100ask_led_pin",

},

};

在设备层chip_demo_gpio.c中通过platform_get_resource()函数将resource中的数据传入设备层,并在.probe = chip_demo_gpio_probe函数中创建device,在.remove = chip_demo_gpio_remove函数中卸载device:

static struct platform_driver chip_demo_gpio_driver = {

.probe = chip_demo_gpio_probe,

.remove = chip_demo_gpio_remove,

.driver = {

.name = "100ask_led",

},

};

static int chip_demo_gpio_probe(struct platform_device *pdev)

{

struct resource *res;

int i = 0;

while (1)

{

res = platform_get_resource(pdev, IORESOURCE_IRQ, i++);

if (!res)

break;

g_ledpins[g_ledcnt] = res->start;

led_class_create_device(g_ledcnt);

g_ledcnt++;

}

return 0;

}

static int chip_demo_gpio_remove(struct platform_device *pdev)

{

struct resource *res;

int i = 0;

while (1)

{

res = platform_get_resource(pdev, IORESOURCE_IRQ, i);

if (!res)

break;

led_class_destroy_device(i);

i++;

g_ledcnt--;

}

return 0;

}

设备层->驱动层

创建device的函数定义在驱动层leddrv.c:led_class_create_device();led_class_destroy_device()定义在驱动层leddrv.c:

static struct class *led_class;

void led_class_create_device(int minor)

{

device_create(led_class, NULL, MKDEV(major, minor), NULL, "100ask_led%d", minor); /* /dev/100ask_led0,1,... */

}

void led_class_destroy_device(int minor)

{

device_destroy(led_class, MKDEV(major, minor));

}

设备层在board_demo_led_opr结构体中对硬件进行设置,并在chip_demo_gpio_drv_init()中使用register_led_operration(&board_demo_led_opr)函数将设备层中结构体led_operations board_demo_led_opr的内容传入驱动层。

led_operations board_demo_led_opr结构体的内容:

/* 在例程中没有对硬件进行操作,只写了一个框架 */

static struct led_operations board_demo_led_opr = {

.init = board_demo_led_init,//在此函数中使能时钟、设置引脚工作模式、设置输入输出模式

.ctl = board_demo_led_ctl,//在此函数中设置引脚电平

};

static int board_demo_led_init (int which) /* 初始化LED, which-哪个LED */

{

//printk("%s %s line %d, led %d\n", __FILE__, __FUNCTION__, __LINE__, which);

printk("init gpio: group %d, pin %d\n", GROUP(g_ledpins[which]), PIN(g_ledpins[which]));

switch(GROUP(g_ledpins[which]))

{

case 0:

{

printk("init pin of group 0 ...\n");

break;

}

case 1:

{

printk("init pin of group 1 ...\n");

break;

}

case 2:

{

printk("init pin of group 2 ...\n");

break;

}

case 3:

{

printk("init pin of group 3 ...\n");

break;

}

}

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(g_ledpins[which]), PIN(g_ledpins[which]));

switch(GROUP(g_ledpins[which]))

{

case 0:

{

printk("set pin of group 0 ...\n");

break;

}

case 1:

{

printk("set pin of group 1 ...\n");

break;

}

case 2:

{

printk("set pin of group 2 ...\n");

break;

}

case 3:

{

printk("set pin of group 3 ...\n");

break;

}

}

return 0;

}

chip_demo_gpio_drv_init()函数:

static int __init chip_demo_gpio_drv_init(void)

{

int err;

err = platform_driver_register(&chip_demo_gpio_driver);

/* 此函数定义在驱动层leddrv.c,在此处使用将board_demo_led_opr中的内容传入驱动层的p_led_opr */

register_led_operations(&board_demo_led_opr);

return 0;

}

设备层leddrv.c中register_led_operration()的定义

struct led_operations *p_led_opr;

void register_led_operations(struct led_operations *opr)

{

p_led_opr = opr;

}

然后通过p_led_opr ->init()和p_led_opr ->ctl()在open和write函数中操作硬件

/* 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,

};

/* 3. 实现对应的open/read/write等函数,填入file_operations结构体 */

/* 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;

}

总结

总结的比较乱,但是目前我也只理解到这一步了,如果以后有了新的思路就再改吧,谢谢观看。

韦东山嵌入式linux驱动开发,学习嵌入式Linux开发——韦东山升级版全系列嵌入式视频之总线设备驱动模型代码分析...相关推荐

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

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

  2. 嵌入式系统开发学习步骤(Linux高级编程学习顺序)

    2019独角兽企业重金招聘Python工程师标准>>> 嵌入式系统开发学习步骤(Linux高级编程学习顺序) 1.Linux 基础 安装Linux操作系统 Linux文件系统 Lin ...

  3. linux驱动开发篇(三)—— 总线设备驱动模型

    linux系列目录: linux基础篇(一)--GCC和Makefile编译过程 linux基础篇(二)--静态和动态链接 ARM裸机篇(一)--i.MX6ULL介绍 ARM裸机篇(二)--i.MX6 ...

  4. linux用户空间flash驱动,全面掌握Linux驱动框架——字符设备驱动、I2C驱动、总线设备驱动、NAND FLASH驱动...

    原标题:全面掌握Linux驱动框架--字符设备驱动.I2C驱动.总线设备驱动.NAND FLASH驱动 字符设备驱动 哈~ 这几天都在发图,通过这种方式,我们希望能帮大家梳理学过的知识,全局的掌握Li ...

  5. Linux总线设备驱动框架的理解(非常棒的文章!)

    以下内容源于微信公众号:嵌入式企鹅圈.有格式内容上的修改,如有侵权,请告知删除. Linux的设备驱动框架,即某类设备对应的驱动的框架. 这里是"Linux总线设备驱动框架",应该 ...

  6. Linux驱动——驱动分离思想和总线设备驱动模型

    驱动分离思想: 在传统的字符设备驱动思想中一个驱动程序对应一个硬件资源,在驱动入口函数中对资源进行配置,在file_operation中对各个硬件资源进行操作.这种思想使得内核中驱动代码变得庞大,为了 ...

  7. Linux SPI总线设备驱动模型详解

    随着技术不断进步,系统的拓扑结构越来越复杂,对热插拔.跨平台移植性的要求越来越高,早期的内核难以满足这些要求,从linux2.6内核开始,引入了总线设备驱动模型.其实在linux2.4总线的概念就已经 ...

  8. 恩施软件开发人员每月多少钱_恩施软件开发学习,恩施软件开发学习哪家好,恩施软件开发学习一般能拿多少工资...

    恩施软件开发学习,恩施软件开发学习哪家好,恩施软件开发学习一般能拿多少工资 首页 > 软件 > 恩施软件开发学习 作者:镀金池   发布时间:2017-11-22 18:54 因为cent ...

  9. linux一个spi总线挂多个设备,Linux SPI总线设备驱动模型详解

    随着技术不断进步,系统的拓扑结构越来越复杂,对热插拔.跨平台移植性的要求越来越高,早期的内核难以满足这些要求,从linux2.6内核开始,引入了总线设备驱动模型.其实在linux2.4总线的概念就已经 ...

  10. 设备驱动模型:总线-设备-驱动

    1 设备驱动模型简介 参考 以下内容: Linux 笔记: https://xuesong.blog.csdn.net/article/details/109522945?spm=1001.2014. ...

最新文章

  1. 工业革命前数千年人口经济_我们已经进行了数千年的编程
  2. 重磅!2021泰晤士世界大学排名公布!
  3. GitHub 大热!也许会成为你心中的OCR开源工具NO1!
  4. mysql lock scope_scope_lock模式详解
  5. #11 硬连接与软链接与RAID与LVM2
  6. saiku docker配置部署_【安装教程】01 Gitea Docker 安装部署 - 【SkywenCode】技术团队基...
  7. 全链路压测自动化实践 1
  8. Git学习总结(4)——我的Git忽略文件与忽略文件提交规则和配置总结
  9. 201506110135陈若倩词法分析实验报告
  10. 李飞飞为什么会离职 Google?
  11. Mac无法开机?如何修复
  12. insmod: can‘t insert ‘xx.ko‘: File exists 问题解决
  13. php代码给用户安装浏览器,PHP判断用户浏览器是否安装alexa工具条程序
  14. 乘风破浪潮头立,扬帆起航正当时——韩国5G商用情况解析
  15. 【Linux】Linux基础命令及英文全称
  16. 2021年中国乳制品行业发展现状分析,“双循环”助力行业发展「图」
  17. LaTeX的正负号写法
  18. 如何实现在直播中播放音频文件
  19. 百度清风算法再次升级,促进下载行业生态良性发展
  20. 在分布式事务(MSDTC)中使用OLE DB数据库连接访问数据

热门文章

  1. Spark SQL 执行计划详解
  2. Google浏览器划词翻译
  3. 《移动应用开发技术——Android》课程报告-个人记账系统
  4. std::vector内存清理
  5. java复制文件拒绝访问权限_关于IO流在复制文件时出现java.io.FileNotFoundException: D:\xxx (拒绝访问。) 拒绝访问的问题...
  6. JSON格式转换工具
  7. python对象销毁(垃圾回收)
  8. 计算机网络期末课后题模2运算CRC
  9. 人脸识别经典算法实现(三)——LBP算法
  10. linux arm 运行exe,ARM_Linux嵌入式开发环境配置