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