接下来我们把后面的代码分析完。
4.parent->child = A first = C2,我们这里不相等,当然我们这里多说一句,如果相等的情况就是我们这次插入的是和A范围相同的资源
此时要把A_作为parent的child,才能实现,后面完整的树的查找遍历。
if (parent->child == first) {
parent->child = new;
} else {
next = parent->child; /* 从A开始查找 */
while (next->sibling != first) /* 找到first C2 (我们这里第一步就找到了) */
next = next->sibling;
next->sibling = new; /* A->sibling = C2_ */
}
return NULL;
可以看到,这是一个很完美的树形结构,从root可以yi'c依次遍历所有的节点。
这里再对比我们之前的分析,做个小结:
1.__insert_resource函数第一次进来parent传的是root,会进入__request_resource,,对于root的child总线所有资源里最小的那个。(比如我们上面的A)
2.之后检查new的范围,和是否要插入的在root范围内,这一次因为root的start和end范围很大,只要参数不传错都是可以成功的,但对其它层可能就会不满足的,即返回传入的节点root。
3.之后对child所属的这一层(相同的parent为同一层,同层之间用sibling连接)从小到大查找是不是,如果小于本层的某个资源,且和本层的资源没重叠,则直接插入,否则退出,返回(如果是没找到,则返回的是本层的最大者的地址,否则如果是重叠了,则返回的是重叠的那个资源的地址)。
4.在__insert_resource里面判断,如果是成功插入,返回NULL,则退出。否则,检查参数,如果是要插入的和返回的有重叠,则break跳出循环,否则调到第2步。
5.之后检查new,如果和本层的某一个资源部分重叠,则不能插入,结束。如果本层查找结束,或小于本层的某一个资源,则跳出。
6.现在说明,new里面至少包含一个完整的资源,接下来就是把new替换掉new包含的部分资源,并把new包含的资源挂接到new下面,同时对挂接层的资源的parent都改为new本身。
7.最后,把new的同层的前一个节点的sibling指向new
这里需要注意的是,加入我们挂接了某个重复资源myled,则之前的资源就挂载它的child里面了
如果我们把myled资源释放掉,则挂载它下面的资源也会释放掉
一个资源下挂载多个
卸载后,都不见了
在这个的基础上
假设我们注册这段资源有部分重复的资源会怎么样
结果如下,会注册失败
最后,我对几个常用的资源注册函数进行分析
void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res);
void __iomem *devm_request_and_ioremap(struct device *dev,
struct resource *res);
void __iomem *devm_request_and_ioremap(struct device *dev,
struct resource *res)
{
void __iomem *dest_ptr;
dest_ptr = devm_ioremap_resource(dev, res);
if (IS_ERR(dest_ptr))
return NULL;
return dest_ptr;
}
/**
* devm_ioremap_resource() - check, request region, and ioremap resource
* @dev: generic device to handle the resource for
* @res: resource to be handled
*
* Checks that a resource is a valid memory region, requests the memory region
* and ioremaps it either as cacheable or as non-cacheable memory depending on
* the resource's flags. All operations are managed and will be undone on
* driver detach.
*
* Returns a pointer to the remapped memory or an ERR_PTR() encoded error code
* on failure. Usage example:
*
* res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
* base = devm_ioremap_resource(&pdev->dev, res);
* if (IS_ERR(base))
* return PTR_ERR(base);
*/
void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res)
{
resource_size_t size;
const char *name;
void __iomem *dest_ptr;
BUG_ON(!dev);
/* 通常我们arm上ioremap的都是mem资源的,不是则退出 */
if (!res || resource_type(res) != IORESOURCE_MEM) {
dev_err(dev, 'invalid resourcen');
return IOMEM_ERR_PTR(-EINVAL);
}
size = resource_size(res); /* 得到资源大小 */
name = res->name ?: dev_name(dev); /* 资源如果申请时没起名,就和设备名一样 */
if (!devm_request_mem_region(dev, res->start, size, name)) { /* 请求资源 */
dev_err(dev, 'can't request region for resource %pRn', res);
return IOMEM_ERR_PTR(-EBUSY);
}
/* ioremap映射物理地址到虚拟地址 */
if (res->flags & IORESOURCE_CACHEABLE)
dest_ptr = devm_ioremap(dev, res->start, size);
else
dest_ptr = devm_ioremap_nocache(dev, res->start, size);
if (!dest_ptr) {
dev_err(dev, 'ioremap failed for resource %pRn', res);
devm_release_mem_region(dev, res->start, size);
dest_ptr = IOMEM_ERR_PTR(-ENOMEM);
}
return dest_ptr;
}
/* IO资源的大小 */
static inline resource_size_t resource_size(const struct resource *res)
{
return res->end - res->start + 1;
}
#define devm_request_mem_region(dev,start,n,name)
__devm_request_region(dev, &iomem_resource, (start), (n), (name))
/*
* Managed region resource
*/
struct region_devres {
struct resource *parent;
resource_size_t start;
resource_size_t n;
};
struct resource * __devm_request_region(struct device *dev,
struct resource *parent, resource_size_t start,
resource_size_t n, const char *name)
{
struct region_devres *dr = NULL;
struct resource *res;
/* 申请空间,管理资源 */
dr = devres_alloc(devm_region_release, sizeof(struct region_devres),
GFP_KERNEL);
if (!dr)
return NULL;
/* 初始化 */
dr->parent = parent;
dr->start = start;
dr->n = n;
/* 申请资源 */
res = __request_region(parent, start, n, name, 0);
if (res)
devres_add(dev, dr); /* 把申请到的资源,加入到该设备中 */
else
devres_free(dr);
return res;
}
static DECLARE_WAIT_QUEUE_HEAD(muxed_resource_wait);
/**
* __request_region - create a new busy resource region
* @parent: parent resource descriptor
* @start: resource start address
* @n: resource region size
* @name: reserving caller's ID string
* @flags: IO resource flags
*/
struct resource * __request_region(struct resource *parent,
resource_size_t start, resource_size_t n,
const char *name, int flags)
{
DECLARE_WAITQUEUE(wait, current);
struct resource *res = alloc_resource(GFP_KERNEL);
if (!res)
return NULL;
/* 填充资源信息 */
res->name = name;
res->start = start;
res->end = start + n - 1;
res->flags = resource_type(parent);
res->flags |= IORESOURCE_BUSY | flags; /* 注意这里默认加了busy标志 */
write_lock(&resource_lock);
for (;;) {
struct resource *conflict;
/* 插入资源(我们之前已经分析过了,插入成功则返回NULL) */
conflict = __request_resource(parent, res);
if (!conflict)
break;
if (conflict != parent) { /* 这次的范围属于申请的范围内,继续查找如果这段资源忙的话,则等待忙完 */
if (!(conflict->flags & IORESOURCE_BUSY)) {
parent = conflict;
continue;
}
}
/* 如果这个资源是多个设备轮换使用的话,把这个设备加入等待队列,等资源可用再被唤醒 */
if (conflict->flags & flags & IORESOURCE_MUXED) {
add_wait_queue(&muxed_resource_wait, &wait);
write_unlock(&resource_lock);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule(); /* 这边直接调度走 */
remove_wait_queue(&muxed_resource_wait, &wait); /* 唤醒说明资源到为了,这里删除掉从等待队列 */
write_lock(&resource_lock);
continue;
}
/* Uhhuh, that didn't work out.. */
free_resource(res);
res = NULL; /* 范围NULL说明没申请到 */
break;
}
write_unlock(&resource_lock);
return res; /* 返回申请到的资源地址 */
}
把该资源加入到资源设备链表中,注销设备时就会释放掉该资源,以及占用的空间。
void devres_add(struct device *dev, void *res)
{
struct devres *dr = container_of(res, struct devres, data);
unsigned long flags;
spin_lock_irqsave(&dev->devres_lock, flags);
add_dr(dev, &dr->node);
spin_unlock_irqrestore(&dev->devres_lock, flags);
}
static void add_dr(struct device *dev, struct devres_node *node)
{
devres_log(dev, node, 'ADD');
BUG_ON(!list_empty(&node->entry));
list_add_tail(&node->entry, &dev->devres_head);
}
这理我们再看一下,申请资源时已经绑定了释放函数,到时候会卸载设备时,采用回调方式的形式,释放掉资源的。
struct resource * __devm_request_region(struct device *dev,
struct resource *parent, resource_size_t start,
resource_size_t n, const char *name)
{
struct region_devres *dr = NULL;
struct resource *res;
dr = devres_alloc(devm_region_release, sizeof(struct region_devres),
GFP_KERNEL);
if (!dr)
return NULL;
dr->parent = parent;
dr->start = start;
dr->n = n;
res = __request_region(parent, start, n, name, 0);
if (res)
devres_add(dev, dr);
else
devres_free(dr);
return res;
}
上一篇:代码示例_中断
下一篇:uboot常用的函数
推荐阅读最新更新时间:2026-03-19 05:57
- 基于 Blackfin 数字信号处理器 (DSP) 的 ADZS-BF518F-EZLITE、ADSP-BF518F EZ-Kit Lite 评估系统
- 使用 ON Semiconductor 的 CAT3200Z 的参考设计
- LTC2162 演示板,16 位 65Msps ADC,LVDS 输出,5-140MHz
- 使用 Analog Devices 的 LTC3526BEDC-2 的参考设计
- LT3091HT7 在极低输出电压下低压降操作的典型应用
- 蓝牙协议分析工具nRF52840 MDK USB Dongle
- NCV2902DR2G 维恩桥振荡器运算放大器的典型应用
- LTC4100EGN 演示板,智能电池充电器 DCIN = 15V-20V / 3.5V
- TC78H620FNG 双桥直流有刷电机驱动器评估板
- 带有 DRP w/Try.SRC 和 Type-C 插座的 PTN5110 USB PD 的典型应用



Linux技术手册
智能机械臂
非常经典的关于LLC的杨波博士论文
XC6406PP60DL






京公网安备 11010802033920号