uboot的驱动模型,简称dm, 具体细节建议参考./doc/driver-model/README.txt
关于dm的三个概念:
uclass:一组同类型的devices,uclass为同一个group的device,提供一个相同的接口。比如:I2C、GPIO等
driver:上层的接口,英文原文解释是“some code which talks to a peripheral and presents a higher-level
    interface to it.”
device:driver的一个实例,绑定到一个具体的端口或者外设。(driver和device是不是可以类比于程序与进程,进程是程序的一个实例)
 
每一类uclass,需要在代码中用下面的方式来定义,以spi-uclass为例:
 
UCLASS_DRIVER(spi) = {
.id = UCLASS_SPI,
.name = "spi",
.flags = DM_UC_FLAG_SEQ_ALIAS,
.post_bind = spi_post_bind,
.post_probe = spi_post_probe,
.child_pre_probe = spi_child_pre_probe,
.per_device_auto_alloc_size = sizeof(struct dm_spi_bus),
.per_child_auto_alloc_size = sizeof(struct spi_slave),
.per_child_platdata_auto_alloc_size =
sizeof(struct dm_spi_slave_platdata),
.child_post_bind = spi_child_post_bind,
};
通过对宏定义UCLASS_DRIVER的展开
/* Declare a new uclass_driver */
#define UCLASS_DRIVER(__name) \
ll_entry_declare(struct uclass_driver, __name, uclass) #define ll_entry_declare(_type, _name, _list) \
_type _u_boot_list_2_##_list##_2_##_name __aligned() \
__attribute__((unused, \
section(".u_boot_list_2_"#_list"_2_"#_name)))
这样我们就能得到一个结构体, struct uclass_driver _u_boot_list_2_uclass_2_spi
并且存在 .u_boot_list_2_uclass_2_spi段。
但是我们如何通过ID UCLASS_SPI来找到对应的uclass结构体呢?
struct uclass_driver *lists_uclass_lookup(enum uclass_id id)
{
// 会根据.u_boot_list_2_uclass_1的段地址来得到uclass_driver table的地址
struct uclass_driver *uclass =
ll_entry_start(struct uclass_driver, uclass); // 获得uclass_driver table的长度
const int n_ents = ll_entry_count(struct uclass_driver, uclass);
struct uclass_driver *entry; for (entry = uclass; entry != uclass + n_ents; entry++) {
if (entry->id == id)
return entry;
} return NULL;
}
可以通过函数lists_uclass_lookup(enum uclass_id id)来查找。
 
另外,driver也是类似
/* Declare a new U-Boot driver */
#define U_BOOT_DRIVER(__name) \
ll_entry_declare(struct driver, __name, driver) #define ll_entry_declare(_type, _name, _list) \
_type _u_boot_list_2_##_list##_2_##_name __aligned() \
__attribute__((unused, \
section(".u_boot_list_2_"#_list"_2_"#_name))) U_BOOT_DRIVER(tegra114_spi) = {
.name = "tegra114_spi",
.id = UCLASS_SPI,
.of_match = tegra114_spi_ids,
.ops = &tegra114_spi_ops,
.ofdata_to_platdata = tegra114_spi_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct tegra_spi_platdata),
.priv_auto_alloc_size = sizeof(struct tegra114_spi_priv),
.probe = tegra114_spi_probe,
};
这样我们就能得到一个结构体,
ll_entry_declare(struct driver, tegra114_spi, driver)

struct driver _u_boot_list_2_driver_2_tegra114_spi
__aligned() \
__attribute__((unused, \
section(".u_boot_list_2_driver_2_tegra114_spi")))
存储在段,.u_boot_list_2_driver_2_tegra114_spi
但是这些段,在uboot实际加载的时候,又是如何加载到链表中去的呢!
 
首先,还是初始化列表init_sequence_f里的函数initf_dm
static int initf_dm(void)
{
#if defined(CONFIG_DM) && defined(CONFIG_SYS_MALLOC_F_LEN)
int ret; ret = dm_init_and_scan(true);
if (ret)
return ret;
#endif
#ifdef CONFIG_TIMER_EARLY
ret = dm_timer_init();
if (ret)
return ret;
#endif return ;
}
dm_init_and_scan(),代码分析如下
int dm_init_and_scan(bool pre_reloc_only)
{
int ret; /*创建udevice和uclass空链表,创建根设备(root device)*/
ret = dm_init();
if (ret) {
debug("dm_init() failed: %d\n", ret);
return ret;
}
/*扫描U_BOOT_DEVICE定义的设备,与U_BOOT_DRIVER定义的driver进行查找,并绑定相应driver*/
ret = dm_scan_platdata(pre_reloc_only);
if (ret) {
debug("dm_scan_platdata() failed: %d\n", ret);
return ret;
} if (CONFIG_IS_ENABLED(OF_CONTROL)) {
/*扫描由FDT设备树文件定义的设备,与U_BOOT_DRIVER定义的driver进行查找,并绑定相应driver*/
ret = dm_scan_fdt(gd->fdt_blob, pre_reloc_only);
if (ret) {
debug("dm_scan_fdt() failed: %d\n", ret);
return ret;
}
}
ret = dm_scan_other(pre_reloc_only);
if (ret)
return ret; return ;
}
分三个部分:
dm_init():创建udevice和uclass空链表,创建根设备(root device)
dm_scan_platdata():调用函数lists_bind_drivers,扫描U_BOOT_DEVICE定义的设备,与U_BOOT_DRIVER定义的driver进行查找,创建udevice,并绑定相应driver。
dm_scan_fdt():扫描由FDT设备树文件定义的设备,与U_BOOT_DRIVER定义的driver进行查找,创建udevice,并绑定相应driver。
int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only)
{
/*从分段,.u_boot_list_2_driver_info中来查找*/
struct driver_info *info =
ll_entry_start(struct driver_info, driver_info); const int n_ents = ll_entry_count(struct driver_info, driver_info);
struct driver_info *entry;
struct udevice *dev;
int result = ;
int ret; for (entry = info; entry != info + n_ents; entry++) {
/*将driver_info列表里面的name,依次与driver列表里面的名字,进行匹配查找,然后进行绑定*/
ret = device_bind_by_name(parent, pre_reloc_only, entry, &dev);
if (ret && ret != -EPERM) {
dm_warn("No match for driver '%s'\n", entry->name);
if (!result || ret != -ENOENT)
result = ret;
}
} return result;
} int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
const struct driver_info *info, struct udevice **devp)
{
struct driver *drv; /*从driver list中查找info的名字*/
drv = lists_driver_lookup_name(info->name);
if (!drv)
return -ENOENT;
if (pre_reloc_only && !(drv->flags & DM_FLAG_PRE_RELOC))
return -EPERM; /*创建udevice,绑定*/
return device_bind(parent, drv, info->name, (void *)info->platdata,
-, devp);
}
U_BOOT_DEVICE的宏定义,注意与U_BOOT_DRIVER的区别:
#define U_BOOT_DEVICE(__name)                        \
ll_entry_declare(struct driver_info, __name, driver_info)
 

uboot的驱动模型理解的更多相关文章

  1. u-boot器件驱动模型(Device&Drivers)之uclass (转)

    一.剧情回顾 在上一篇链接器的秘密里面我们讲到我们用一些特殊的宏让链接器帮我们把一些初始化好的结构体列好队并安排在程序的某一个段里面,这里我例举出了三个和我们主题相关段的分布情况,它们大概如下图所示: ...

  2. uboot 网络驱动模型

    原文:https://blog.csdn.net/zhouxinlin2009/article/details/45390065 UBOOT的PHYCHIP配置 PHYCHIP的配置位于 includ ...

  3. [uboot] (番外篇)uboot 驱动模型(转)重要

    [uboot] uboot流程系列:[project X] tiny210(s5pv210)上电启动流程(BL0-BL2)[project X] tiny210(s5pv210)从存储设备加载代码到D ...

  4. u-boot下的DM驱动模型 阶梯状 (转)

    U-boot 下DM驱动模型的相关笔记要注意的关键两点: DM驱动模型的一般流程bind->ofdata_to_platdata(可选)->probe    启动,bind操作时单独完成的 ...

  5. usb驱动开发4之总线设备驱动模型

    在上文说usb_init函数,却给我们留下了很多岔路口.这次就来好好聊聊关于总线设备驱动模型.这节只讲理论,不讲其中的函数方法,关于函数方法使用参考其他资料. 总线.设备.驱动对应内核结构体分别为bu ...

  6. linux驱动模型<输入子系统>

    在linux中提供一种输入子系统的驱动模型,其主要是实现在input.c中. 在输入子系统这套模型中,他把驱动分层分类.首先分为上下两层,上层为input.c .下层为驱动的实现,下层分为两部分,一部 ...

  7. linux RTC 驱动模型分析【转】

    转自:http://blog.csdn.net/yaozhenguo2006/article/details/6824970 RTC(real time clock)实时时钟,主要作用是给Linux系 ...

  8. 字符设备驱动、平台设备驱动、设备驱动模型、sysfs的比较和关联

    转载自:http://www.kancloud.cn/yueqian_scut/emlinux/106829 学习Linux设备驱动开发的过程中自然会遇到字符设备驱动.平台设备驱动.设备驱动模型和sy ...

  9. linux内核驱动模型

    linux内核驱动模型,以2.6.32内核为例.(一边写一边看的,有点乱.) 1.以内核对象为基础.用kobject表示,相当于其它对象的基类,是构建linux驱动模型的关键.具有相同类型的内核对象构 ...

随机推荐

  1. 【转】数据库事务ACID以及事务隔离

      本篇讲诉数据库中事务的四大特性(ACID),并且将会详细地说明事务的隔离级别. 如果一个数据库声称支持事务的操作,那么该数据库必须要具备以下四个特性: ⑴ 原子性(Atomicity) 原子性是指 ...

  2. springCloud系列 Config配置中心

    1.config服务的部署 2.yum文件的格式 大小写敏感 使用缩进表示层级关系 缩进时不允许使用Tab键,只允许使用空格. 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可 3.热部署 4.配 ...

  3. [ 搭建Redis本地服务器实践系列三 ] :图解Redis客户端工具连接Redis服务器

    上一章 [ 搭建Redis本地服务器实践系列二 ] :图解CentOS7配置Redis  介绍了Redis的初始化脚本文件及启动配置文件,并图解如何以服务的形式来启动.终止Redis服务,可以说我们的 ...

  4. 基于opencv3.0下的运动车辆识别

    在opencv的初等应用上,对运动物体的识别主要有帧差或背景差两种方式. 帧差法主要的原理是当前帧与前一帧作差取绝对值: 背景差主要的原理是当前帧与背景帧作差取绝对值: 在识别运动车辆上主要需要以下9 ...

  5. SpringBoot 同时整合thymeleaf html、vue html和jsp

    问题描述 SpringBoot如何同时访问html和jsp SpringBoot访问html页面可以,访问jsp页面报错 SpringBoot如何同时整合thymeleaf html.vue html ...

  6. jquery开关按钮效果

    .circular1{ width: 50px; height: 30px; border-radius: 16px; background-color: #ccc; transition: .3s; ...

  7. python基础autopep8__python代码规范

    关于PEP 8 PEP 8,Style Guide for Python Code,是Python官方推出编码约定,主要是为了保证 Python 编码的风格一致,提高代码的可读性. 官网地址:http ...

  8. python教你用微信每天给女朋友说晚安

    但凡一件事,稍微有些重复.我就考虑怎么样用程序来实现它. 这里给各位程序员朋友分享如何每天给朋友定时微信发送"晚安",故事,新闻,等等··· ···最好运行在服务器上,这样后台挂起 ...

  9. Java Script 读书笔记 (三) 函数

    1. 函数作用域 在函数内部定义的变量,外部无法读取,称为"局部变量"(local variable). 变量v在函数内部定义,所以是一个局部变量,函数之外就无法读取. 函数内部定 ...

  10. random.nextInt()与Math.random()基础用法

    相关文章:关于Random(47)与randon.nextInt(100)的区别 1.来源 random.nextInt() 为 java.util.Random类中的方法: Random类中还提供各 ...