步步为营,分析平台设备初始化platform_device_register()


linux2.6.30外设等设备,会在上电的时候,整体初始化;然后,设备驱动初始化;再然后,系统运行的时候,设备的热插拔才会被系统识别。。。。

那么,系统上电时的设备初始化,如何进行。如何管理。

为了一探究竟,先从平台设备注册函数看起platform_device_register()

//base_platform.c
/**
 * platform_device_register - add a platform-level device
 * @pdev: platform device we're adding
 */
int platform_device_register(struct platform_device *pdev)
{
	device_initialize(&pdev->dev);
	return platform_device_add(pdev);
}
首先,看看传入参数是怎么定义的吧!

struct platform_device {
	const char	* name;<span style="white-space:pre">	</span>//设备名,什么的样的设备什么样的驱动程序来驱动工作,匹配查找的时候需要此name的compare
	int		id;<span style="white-space:pre">	</span>//设备ID,同一个驱动对应多个设备,比如一个串口驱动就可以驱动几个串口设备,一个道理。
	struct device	dev;<span style="white-space:pre">	</span>//设备信息 设备驱动地址 ,这个变量,会在真正驱动设备的时候进行赋值
	u32		num_resources;//内存地址的个数
	struct resource	* resource;//设备内存地址 memory address 包括寄存器地址 和 中断号等信息

	struct platform_device_id	*id_entry;//平台设备ID入口 后边driver和device 匹配的时候,会用到此变量
};
入口参数介绍完了,现在可以简单看下设备注册函数都做了什么事?

两件事:设备信息初始化、添加设备

1)、设备信息初始化

如何初始化的,先看代码

</pre><pre name="code" class="cpp">/**
 * device_initialize - init device structure.
 * @dev: device.
 *
 * This prepares the device for use by other layers by initializing
 * its fields.
 * It is the first half of device_register(), if called by
 * that function, though it can also be called separately, so one
 * may use @dev's fields. In particular, get_device()/put_device()
 * may be used for reference counting of @dev after calling this
 * function.
 *
 * NOTE: Use put_device() to give up your reference instead of freeing
 * @dev directly once you have called this function.
 */
void device_initialize(struct device *dev)
{
	dev->kobj.kset = devices_kset;<span style="font-family:Courier New;font-size:12px;color:#008000;"><em>//kset to creat /sys/devices 指向sys目录下的device目录,方便后续建立设备信息sysfs</em></span>
	kobject_init(&dev->kobj, &device_ktype);//初始化设备在sysfs内的操作信息、操作选项,将设备在sys目录下的内容作链表存储,便于查找和显示
	INIT_LIST_HEAD(&dev->dma_pools);//初始化dma 池
	init_MUTEX(&dev->sem);//信号量初始化
	spin_lock_init(&dev->devres_lock);//dev resource 自旋锁初始化
	INIT_LIST_HEAD(&dev->devres_head);//devres 链表初始化
	device_init_wakeup(dev, 0);//
	device_pm_init(dev);
	set_dev_node(dev, -1);
}
第二个步骤就是将设备添加到总线上

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

	<span style="color:#ff6666;">if (pdev->id != -1)
		dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
	else
		dev_set_name(&pdev->dev, pdev->name);<em>//设备id有些预先设置了,没预先初始化的,此时初始化。比如串口已经初始化,串口依次1 2 3 4.。。</em></span>
<span style="white-space:pre">						</span><em><span style="color:#ff0000;">//name可能就会被设置成 uart1 .....</span></em>
<span style="white-space:pre">	</span>/*
<span style="white-space:pre">		</span>下面的这段for代码,主要是为了将设备归类,是IO,还是irq?还是MEM?还是DMA?等等。。。
<span style="white-space:pre">		</span>设备划分宏定义,见后续。判断的标准主要是变量flag的 bit8-bit11
<span style="white-space:pre">	</span>*/
	for (i = 0; i < pdev->num_resources; i++) {
		struct resource *p, *r = &pdev->resource[i];

		if (r->name == NULL)
			r->name = dev_name(&pdev->dev);

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

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

	pr_debug("Registering platform device '%s'. Parent at %s\n",
		 dev_name(&pdev->dev), dev_name(pdev->dev.parent));
<span style="white-space:pre">	</span>//关键的关键,就是这个设备添加函数,具体分析见下节吧
	ret = device_add(&pdev->dev);
	if (ret == 0)
		return ret;

 failed:
	while (--i >= 0) {
		struct resource *r = &pdev->resource[i];
		unsigned long type = resource_type(r);

		if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
			release_resource(r);
	}

	return ret;
}
EXPORT_SYMBOL_GPL(platform_device_add);

设备类型划分

#define IORESOURCE_IO		0x00000100
#define IORESOURCE_MEM		0x00000200
#define IORESOURCE_IRQ		0x00000400
#define IORESOURCE_DMA		0x00000800



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值