文章的分析基於linux-2.6.22,led驅動分析了s3c24xx的led設備的註冊、驅動的註冊,以及其設備和驅動的關聯過程;platform_bus_init過程分析了platform_bus設備的註冊。 platform_bus設備,platform_device設備,device設備,到底有多少名字近似的設備啊?
今天學習下platform_device設備,儘量把幾個概念搞清楚。
1.
void __init smdk_machine_init(void)
{
......
platform_add_devices(smdk_devs, ARRAY_SIZE(smdk_devs));
......
}
static struct platform_device __initdata *smdk_devs[] = {
.......
&smdk_led4, //這個就是platform_device設備了
......
};
static struct platform_device smdk_led4 = {
.name = "s3c24xx_led",
.id = 0,
.dev = {
.platform_data = &smdk_pdata_led4,
},
};
2.
/**
* platform_add_devices - add a numbers of platform devices
* @devs: array of platform devices to add
* @num: number of platform devices in array
*/
int platform_add_devices(struct platform_device **devs, int num)
{
int i, ret = 0;
for (i = 0; i < num; i++) {
ret = platform_device_register(devs[i]); //註冊platform_device設備
if (ret) {
while (--i >= 0)
platform_device_unregister(devs[i]);
break;
}
}
return ret;
}
3. //以前看這裏發懵:add到哪?
/**
* 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); //3.1分析
return platform_device_add(pdev); //3.2分析
}
3.1 //設置platform_device的kset指向devices_subsys
/**
* device_initialize - init device structure.
* @dev: device.
*
* This prepares the device for use by other layers,
* including adding it to the device hierarchy.
* It is the first half of device_register(), if called by
* that, though it can also be called separately, so one
* may use @dev's fields (e.g. the refcount).
*/
//devices_subsys的目錄名爲devices
void device_initialize(struct device *dev)
{
......
kobj_set_kset_s(dev, devices_subsys); //設置dev的kset指向devices_subsys
.......
INIT_LIST_HEAD(&dev->node);
.......
}
3.2
/**
* 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)
{
......
if (!pdev->dev.parent)
pdev->dev.parent = &platform_bus;
pdev->dev.bus = &platform_bus_type; //以前對這個platform_bus_type沒認知
if (pdev->id != -1)
snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%u", pdev->name, pdev->id);
......
ret = device_add(&pdev->dev);
......
}
3.2.1
/**
* device_add - add device to device hierarchy.
* @dev: device.
*
* This is part 2 of device_register(), though may be called
* separately _iff_ device_initialize() has been called separately.
*
* This adds it to the kobject hierarchy via kobject_add(), adds it
* to the global and sibling lists for the device, then
* adds it to the other relevant subsystems of the driver model.
*/
int device_add(struct device *dev)
{
......
/* first, register with generic layer. */
kobject_set_name(&dev->kobj, "%s", dev->bus_id);
error = kobject_add(&dev->kobj); //將dev_kobj接入platform_bus(kset)的鏈表
......
bus_attach_device(dev); //將dev接入bus的鏈表
......
}
3.2.3
/**
* bus_attach_device - add device to bus
* @dev: device tried to attach to a driver
*
* - Add device to bus's list of devices.
* - Try to attach to driver.
*/
void bus_attach_device(struct device * dev)
{
struct bus_type *bus = dev->bus;
int ret = 0;
if (bus) {
dev->is_registered = 1;
if (bus->drivers_autoprobe)
ret = device_attach(dev);
WARN_ON(ret < 0);
if (ret >= 0)
klist_add_tail(&dev->knode_bus, &bus->klist_devices); //添加到bus的list鏈表
else
dev->is_registered = 0;
}
}
添加的設備與platform_bus_type和platform_bus的關係如下圖,從圖中很容易解答我心中的的疑惑: