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

2019-04-14 21:23发布

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; //设备名,什么的样的设备什么样的驱动程序来驱动工作,匹配查找的时候需要此name的compare int id; //设备ID,同一个驱动对应多个设备,比如一个串口驱动就可以驱动几个串口设备,一个道理。 struct device dev; //设备信息 设备驱动地址 ,这个变量,会在真正驱动设备的时候进行赋值 u32 num_resources;//内存地址的个数 struct resource * resource;//设备内存地址 memory address 包括寄存器地址 和 中断号等信息 struct platform_device_id *id_entry;//平台设备ID入口 后边driver和device 匹配的时候,会用到此变量 }; 入口参数介绍完了,现在可以简单看下设备注册函数都做了什么事? 两件事:设备信息初始化、添加设备 1)、设备信息初始化 如何初始化的,先看代码
/**
 * 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;//kset to creat /sys/devices 指向sys目录下的device目录,方便后续建立设备信息sysfs
	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; if (pdev->id != -1) dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); else dev_set_name(&pdev->dev, pdev->name);//设备id有些预先设置了,没预先初始化的,此时初始化。比如串口已经初始化,串口依次1 2 3 4.。。 //name可能就会被设置成 uart1 ..... /* 下面的这段for代码,主要是为了将设备归类,是IO,还是irq?还是MEM?还是DMA?等等。。。 设备划分宏定义,见后续。判断的标准主要是变量flag的 bit8-bit11 */ 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 ", dev_name(&pdev->dev), i); ret = -EBUSY; goto failed; } } pr_debug("Registering platform device '%s'. Parent at %s ", dev_name(&pdev->dev), dev_name(pdev->dev.parent)); //关键的关键,就是这个设备添加函数,具体分析见下节吧 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