韦东山二期驱动视频-platform机制

同样,这个点也是面试中层遇到的问题,不过当时确实没有说清楚。

为什么内核要引入这个机制?

个人理解为,这个机制使得driver和device相对的分离了。而且对于同一类的设备,更好更方便管理。

进入正题:

********************************************************************************************************************

platform机制由内核中的platform.c实现,文件位于linux-2.6.22.6\drivers\base\platform.c

从入口开始看起,发现和输入子系统不同的时,没有module_init函数,那么很可能是这个platform其实也是被其他文件调用的

根据c语言先声明后使用的原则,从文档末往前看,发现一个函数    platform_bus_init();嗯,从名字看就是“入口函数”

使用si4.0搜索caller,发现被linux-2.6.22.6\drivers\base\init.c调用,看名字推断,系统的init进程会调用这个函数,那么就去看这个函数干了啥,推测也是搭建一个框架即平台。

int __init platform_bus_init(void)
{
	int error;

	error = device_register(&platform_bus);
	if (error)
		return error;
	error =  bus_register(&platform_bus_type);
	if (error)
		device_unregister(&platform_bus);
	return error;
}

逐行分析,

首先,注册设备,注册一个平台设备

然后,注册一个总线

问题来了,这个时候,注册的总线和平台原料从哪来?

struct device platform_bus = {
	.bus_id		= "platform",
};
struct bus_type platform_bus_type = {
	.name		= "platform",
	.dev_attrs	= platform_dev_attrs,
	.match		= platform_match,
	.uevent		= platform_uevent,
	.suspend	= platform_suspend,
	.suspend_late	= platform_suspend_late,
	.resume_early	= platform_resume_early,
	.resume		= platform_resume,
};

注册的时候具体干了啥工作?注册并添加到设备链表中,这就回到了输入子系统中的设备注册流程

int device_register(struct device *dev)
{
	device_initialize(dev);
	return device_add(dev);
}

也就说,系统在初始化时,注册了id为platform的总线,第二个结构体中含有多个函数,可能要在设备或者驱动注册时再去调用。

那么下面就结合韦东山的led驱动程序去分析调用:

首先是设备的注册,

static int led_dev_init(void)
{
	platform_device_register(&led_dev);
	return 0;
}

首先调用下面的函数,从形式上看,跟上面平台的注册是多么类似,都是先书初始化,再去添加,不过这次是添加到了platform_device_add链表中,可见是一层套一层

int platform_device_register(struct platform_device * pdev)
{
	device_initialize(&pdev->dev);
	return platform_device_add(pdev);
}

设备的初始化暂时不去看,先看添加到链表。


/**
 *	platform_device_add - add a platform device to device hierarchy
 *	@pdev:	platform device we're adding
 *
 *	This is part 2 of platform_device_register(), though may be called
 *	separately _iff_ pdev was allocated by platform_device_alloc().
 */
int platform_device_add(struct platform_device *pdev)
{
	int i, ret = 0;

	if (!pdev)
		return -EINVAL;

	if (!pdev->dev.parent)
		pdev->dev.parent = &platform_bus;

	pdev->dev.bus = &platform_bus_type;

	if (pdev->id != -1)
		snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%u", pdev->name, pdev->id);
	else
		strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);

	for (i = 0; i < pdev->num_resources; i++) {
		struct resource *p, *r = &pdev->resource[i];

		if (r->name == NULL)
			r->name = pdev->dev.bus_id;

		p = r->parent;
		if (!p) {
			if (r->flags & IORESOURCE_MEM)
				p = &iomem_resource;
			else if (r->flags & IORESOURCE_IO)
				p = &ioport_resource;
		}

		if (p && insert_resource(p, r)) {
			printk(KERN_ERR
			       "%s: failed to claim resource %d\n",
			       pdev->dev.bus_id, i);
			ret = -EBUSY;
			goto failed;
		}
	}

	pr_debug("Registering platform device '%s'. Parent at %s\n",
		 pdev->dev.bus_id, pdev->dev.parent->bus_id);

	ret = device_add(&pdev->dev);
	if (ret == 0)
		return ret;

 failed:
	while (--i >= 0)
		if (pdev->resource[i].flags & (IORESOURCE_MEM|IORESOURCE_IO))
			release_resource(&pdev->resource[i]);
	return ret;
}

逐行分析,其中这一点应该也是创建设备文件节点,在这里id=-1,所以执行else分支,

	if (pdev->id != -1)
		snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%u", pdev->name, pdev->id);
	else
		strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);

将最多BUS_ID_SIZE=20个字节拷贝到bus_id中,也就是将"myled"拷贝到了pdev->dev.bus_id,

然后,统计并整理这个设备的资源,可以看到这里去分别统计了IORESOURCE_MEM和IORESOURCE_IO两种

最后添加设备

但是上述过程并没有看到,platform在知道设备注册后,做了什么操作,所以肯定有遗漏,需要在梳理一遍

 

 

 

 

 

 

 

 

待续》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值