内核版本:linux-3.10.61
目录
2-1、struct bus_type platform_bus_type;
3、platform_device_register() 分析
4、platform_driver_register() 分析
本文主要通过分析注册函数platform_device_register()和platform_driver_register(),得到platform_device和platform_driver之间如何匹配成功。具体的匹配过程和小蝌蚪找妈妈类似,匹配每个对象,直到小蝌蚪找到妈妈。
Platform 平台设备设备驱动模型的作用是将驱动的实现和资源分离,是一个虚拟的总线平台。这其中存在三个成员platform_bus,platform_device,platform_driver。platform_device和platform_driver注册不分先后顺序,因为在注册时都会去匹配对方,这一点可以在我们分析注册函数时证实。
platform_bus:由链表实现,不对应实际的物理总线。
platform_device:驱动的资源比如一些 I/O端口,中断号之类的。
platform_driver:驱动的功能实现比如 注册驱动,实现file_operations 等
这是一个全局结构体用于描述一个platform_bus。platform_driver和platform_device会被挂到这个bus结构体里面。其中match成员用于platform_device和platform_driver之间的匹配,详情请看后面对注册函数的分析。
struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};
主要用于保存硬件资源。name成员用于匹配driver。resource 用于存放需要用到的资源。
struct platform_device {
const char *name; // 用于匹配platform_driver->id_table->name
int id;
bool id_auto;
struct device dev; // 设备结构体
u32 num_resources; // 资源个数
struct resource *resource; // 资源数据(通常用数组表示)
const struct platform_device_id *id_entry;
/* MFD cell pointer */
struct mfd_cell *mfd_cell;
/* arch specific additions */
struct pdev_archdata archdata;
};
struct resource {
resource_size_t start; // 资源的起始地址
resource_size_t end; // 资源结束地址
const char *name; // 名称
unsigned long flags; // 资源类型:IRQ,MEM,IO等,使用宏 ‘IORESOURCE_*’ 表示
struct resource *parent, *sibling, *child;
};
用于描述驱动的实现。通过platform_driver 的name成员匹配上device后probe成语会被调用。在设备拔出时系统会调用remove成员做清理工作。
struct platform_driver {
int (*probe)(struct platform_device *); // device和driver的name匹配成功后调用probe函数
int (*remove)(struct platform_device *); // 设备移除时调用
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*resume)(struct platform_device *);
struct device_driver driver; // id_table->name没有设置时,使用driver->name 进行匹配
const struct platform_device_id *id_table;
};
struct platform_device_id {
char name[PLATFORM_NAME_SIZE]; // 用来和platform_device->name进行匹配
kernel_ulong_t driver_data;
};
/* platform_device注册和卸载函数。 */
int platform_device_register(struct platform_device *pdev);
void platform_device_unregister(struct platform_device *pdev);
/* platform_driver注册和卸载函数。 */
int platform_driver_register(struct platform_driver *drv);
void platform_driver_unregister(struct platform_driver *drv);
/* 获取platform_device中保存的资源 */
struct resource *platform_get_resource(struct platform_device *dev,
unsigned int type, unsigned int num);
/* 获取platform_device的中断资源 */
int platform_get_irq(struct platform_device *dev, unsigned int num)
/* 用于批量注册平台设备 */
int platform_add_devices(struct platform_device **devs, int num)
platform_device_register()用于注册一个platform_device,让我们一起来看看struct platform_device是如何注册进总线的。
int platform_device_register(struct platform_device *pdev)
{
device_initialize(&pdev->dev);
arch_setup_pdev_archdata(pdev);
return platform_device_add(pdev);
}
int platform_device_add(struct platform_device *pdev){
if (!pdev->dev.parent)
pdev->dev.parent = &platform_bus;
/* ...略 */
pdev->dev.bus = &platform_bus_type; // 用在2-1提到的bus全局结构体初始化pdev->dev.bus
/* ...略 */
ret = device_add(&pdev->dev); // 来看看它做了点什么
/* ...略 */
}
int device_add(struct device *dev){
/* ...略 */
error = bus_add_device(dev); // 将device 添加到bus总线
bus_probe_device(dev); // 匹配总线中同名的driver
/* ...略 */
}
/* device 在这里挂接到bus中 */
int bus_add_device(struct device *dev){
klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices); // device 挂接到platform bus
}
void bus_probe_device(struct device *dev)
{
ret = device_attach(dev); // 在这里去匹配总线上有没有同名的driver
}
int device_attach(struct device *dev){
/* ...略 */
/* 使用 __device_attach 和总线上的所有driver匹配*/
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
}
static int __device_attach(struct device_driver *drv, void *data)
{
struct device *dev = data;
if (!driver_match_device(drv, dev)) // 在这里调用platform_bus_type.match 函数用于匹配总线上的driver
return 0;
/* 匹配成功调用 driver_probe_device*/
return driver_probe_device(drv, dev); // 先买个关子,先不分析它,因为我猜platform_driver_register()也会调用到它
}
static inline int driver_match_device(struct device_driver *drv,
struct device *dev)
{
return drv->bus->match ? drv->bus->match(dev, drv) : 1; // 这个match函数指向platform_match()
}
platform_match()用于匹配device和driver。一起来看看device和driver是怎么互相匹配的。
static int platform_match(struct device *dev, struct device_driver *drv){
/* Then try to match against the id table */
if (pdrv->id_table) // id_table 设置了,就同过id_table进行匹配
return platform_match_id(pdrv->id_table, pdev) != NULL;
/* fall-back to driver name match */
return (strcmp(pdev->name, drv->name) == 0); // id_table 未设置使用driver->name进行匹配
}
static const struct platform_device_id *platform_match_id(
const struct platform_device_id *id,
struct platform_device *pdev){
if (strcmp(pdev->name, id->name) == 0) // device->name和driver->id_table->name 进行匹配
;
}
platform_driver_register()用于注册platform_driver。关于platform_driver 是怎么通过platform_driver_register() 注册进总线的,让我们一层一层给它剥出来。看完前面剥好的platform_device_register(),下边你就能看到很多熟人了。
int platform_driver_register(struct platform_driver *drv)
{
drv->driver.bus = &platform_bus_type;
if (drv->probe)
drv->driver.probe = platform_drv_probe; // 第一个熟人driver.probe,device和driver匹配成功后就会调用它
if (drv->remove)
drv->driver.remove = platform_drv_remove;
if (drv->shutdown)
drv->driver.shutdown = platform_drv_shutdown;
return driver_register(&drv->driver); // 这是个新人,我们盘它
}
int driver_register(struct device_driver *drv){
ret = bus_add_driver(drv); // 把driver 添加到 platform bus。和bus_add_device()是两兄弟
}
int bus_add_driver(struct device_driver *drv){
struct driver_private *priv;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
klist_init(&priv->klist_devices, NULL, NULL);
priv->driver = drv;
drv->p = priv;
priv->kobj.kset = bus->p->drivers_kset;
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
error = driver_attach(drv); // 这儿去匹配device, 和device_attach() 是两兄弟
}
int driver_attach(struct device_driver *drv)
{
/* 使用__driver_attach和总线上的所有device匹配 */
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}
static int __driver_attach(struct device *dev, void *data){
if (!driver_match_device(drv, dev)) // 同样的在这里调用platform_bus_type.match 函数用于匹配driver
return 0; // 匹配失败返回
/*
* 果然和我们猜的一样这里也调用到了driver_probe_device()
* 看到这里就已经离最终的答案很近了,再坚持一下,谜底很快就要揭晓了
*/
driver_probe_device(drv, dev);
}
让我们来看一下穿山甲到底说了什么,一起揭晓谜底。
int driver_probe_device(struct device_driver *drv, struct device *dev){
/* ...略 */
ret = really_probe(dev, drv); // 调用drv的prob函数
}
static int really_probe(struct device *dev, struct device_driver *drv){
/* ...略 */
if (dev->bus->probe) {
ret = dev->bus->probe(dev);
if (ret)
goto probe_failed;
} else if (drv->probe) {
ret = drv->probe(dev); // 调用到driver的probe
if (ret)
goto probe_failed;
}
}
static int platform_drv_probe(struct device *_dev)
{
struct platform_driver *drv = to_platform_driver(_dev->driver);
struct platform_device *dev = to_platform_device(_dev);
ret = drv->probe(dev); // 最终我们调用到了 platform_driver->probe()函数,也就是我们自己定义的probe函数
return ret;
}
让我们在内核找一个设备驱动代码来解释一下
注册一个platform_device
static struct platform_device am79c961_device = {
.name = "am79c961",
.id = -1,
.num_resources = ARRAY_SIZE(am79c961_resources),
.resource = am79c961_resources,
};
static struct platform_device *ebsa110_devices[] = {
&serial_device,
&am79c961_device,
};
static int __init ebsa110_init(void)
{
arm_pm_idle = ebsa110_idle;
/*platform_add_devices 函数内部也是调用platform_device_register() */
return platform_add_devices(ebsa110_devices, ARRAY_SIZE(ebsa110_devices));
}
注册一个platform_driver
static struct platform_driver am79c961_driver = {
.probe = am79c961_probe, // 匹配成功后调用
.driver = {
.name = "am79c961",
},
};
static int __init am79c961_init(void)
{
return platform_driver_register(&am79c961_driver);
}
匹配成功后调用驱动自己的probe函数初始化。
static int am79c961_probe(struct platform_device *pdev){
res = platform_get_resource(pdev, IORESOURCE_IO, 0); // 获取device端定义的资源
ret = platform_get_irq(pdev, 0); // 获取device端定义中断资源
ret = register_netdev(dev); // 注册设备(网络设备)
}
恭喜获得知识点+1
若有讲解不妥之处烦请在评论区指正!
如果有收获那就一键三连鼓励一下吧!