platform 总线

platform总线式后面引入的一种虚拟总线,采用此总线编写的驱动分为两端device和driver,给人一种软硬分离的感觉,device端包含设备的资源由内核统一管理,driver使用时就从内核取出来,这种结构层次分明,大大提高了驱动程序的可移植性。

先来看下主要源代码:

struct platform_device {
const char * name;//设备名用来匹配device和driver的
int id;//设备号
struct device dev;
u32 num_resources;
struct resource * resource;//设备资源
const struct platform_device_id *id_entry;

/* arch specific additions */
struct pdev_archdata archdata;
};

struct resource {
resource_size_t start;//开始
resource_size_t end;//结束
const char *name;//名字
unsigned long flags;//资源类型
struct resource *parent, *sibling, *child;
};

获取资源函数,常在probe函数中使用

/**
 * platform_get_resource - get a resource for a device
 * @dev: platform device
 * @type: resource type
 * @num: resource index
 */
struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num)

device构建过程:

1》构造platform_device结构

使用struct platform_device *platform_device_alloc(const char *name, int id)//动态创建platform_device

或者手动填充platform_device结构

2》将platform_device接入平台总线

动态创建的使用platform_device_add(platform_device *pdev);

手动填充的使用platform_device_register(platform_device *pdev);

看一下platform_device_register

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

最终还是调用了platform_device_add



struct platform_driver {
int (*probe)(struct platform_device *);//device和driver匹配时调用
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;//driver结构
const struct platform_device_id *id_table;
};

struct device_driver {
const char *name;//和前面的device name对应
struct bus_type *bus;


struct module *owner;
const char *mod_name; /* used for built-in modules */


bool suppress_bind_attrs; /* disables bind/unbind via sysfs */


#if defined(CONFIG_OF)
const struct of_device_id *of_match_table;
#endif

int (*probe) (struct device *dev);
int (*remove) (struct device *dev);
void (*shutdown) (struct device *dev);
int (*suspend) (struct device *dev, pm_message_t state);
int (*resume) (struct device *dev);
const struct attribute_group **groups;
const struct dev_pm_ops *pm;
struct driver_private *p;
};

device和driver是怎样匹配的呢?

进入platform_driver_register 函数查看

/**
 * platform_driver_register - register a driver for platform-level devices
 * @drv: platform driver structure
 */
int platform_driver_register(struct platform_driver *drv)
{
drv->driver.bus = &platform_bus_type;
if (drv->probe)
drv->driver.probe = platform_drv_probe;
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)
{
int ret;
struct device_driver *other;


BUG_ON(!drv->bus->p);


if ((drv->bus->probe && drv->probe) ||
   (drv->bus->remove && drv->remove) ||
   (drv->bus->shutdown && drv->shutdown))
printk(KERN_WARNING "Driver '%s' needs updating - please use "
"bus_type methods\n", drv->name);


other = driver_find(drv->name, drv->bus);
if (other) {
put_driver(other);
printk(KERN_ERR "Error: Driver '%s' is already registered, "
"aborting...\n", drv->name);
return -EBUSY;
}


ret = bus_add_driver(drv);
if (ret)
return ret;
ret = driver_add_groups(drv, drv->groups);
if (ret)
bus_remove_driver(drv);
return ret;
}


int bus_add_driver(struct device_driver *drv)
{
struct bus_type *bus;
struct driver_private *priv;
int error = 0;


bus = bus_get(drv->bus);
if (!bus)
return -EINVAL;


pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);


priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
error = -ENOMEM;
goto out_put_bus;
}
klist_init(&priv->klist_devices, NULL, NULL);
priv->driver = drv;
drv->p = priv;
priv->kobj.kset = bus->p->drivers_kset;
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
    "%s", drv->name);
if (error)
goto out_unregister;


if (drv->bus->p->drivers_autoprobe) {
error = driver_attach(drv);
if (error)
goto out_unregister;
}
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
module_add_driver(drv->owner, drv);


error = driver_create_file(drv, &driver_attr_uevent);
if (error) {
printk(KERN_ERR "%s: uevent attr (%s) failed\n",
__func__, drv->name);
}
error = driver_add_attrs(bus, drv);
if (error) {
/* How the hell do we get out of this pickle? Give up */
printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
__func__, drv->name);
}


if (!drv->suppress_bind_attrs) {
error = add_bind_files(drv);
if (error) {
/* Ditto */
printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
__func__, drv->name);
}
}


kobject_uevent(&priv->kobj, KOBJ_ADD);
return 0;


out_unregister:
kobject_put(&priv->kobj);
kfree(drv->p);
drv->p = NULL;
out_put_bus:
bus_put(bus);
return error;
}

由于源代码有点多就不展开了driver_attach再调用bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);,__driver_attach中driver_probe_device(drv, dev);

查看最后的driver_probe_device代码

int driver_probe_device(struct device_driver *drv, struct device *dev)
{
int ret = 0;


if (!device_is_registered(dev))
return -ENODEV;


pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
drv->bus->name, __func__, dev_name(dev), drv->name);



pm_runtime_get_noresume(dev);
pm_runtime_barrier(dev);
ret = really_probe(dev, drv);
pm_runtime_put_sync(dev);


return ret;
},

最后调用device_is_registered  查看dev有没有在总线上注册,有就调用probe函数,我们这是从driver端分析匹配过程,你也可以从device端分析下过程


代码:

platform_device端:

static struct platform_device *myplat_dev;
static int __init myplatform_init()
{
myplat_dev = platform_device_alloc("myplatform",1);
platform_device_add(&myplat_dev);
//platform_device_register(&myplat_dev);
return 0;
}


static void __exit myplatform_exit()
{
platform_device_unregister(&myplat_dev);
}


module_init(myplatform_init);
module_exit(myplatform_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Liwenzou");

platform_driver端:

static int myplatform_probe(struct platform_device *pdev)
{
struct platform_device *mydev = pdev;
printk("driver and device successfully match!\n");
return 0;
}
static int myplatform_remove(struct platform_device *pdev)
{
printk("platform is remove !!");
return 0;
}
static struct platform_driver myplatform_driver = {
.probe = myplatform_probe,
.remove = myplatform_remove,
.driver = {
.name = "myplatform",
.owner = THIS_MODULE,
},
};


static int __init platform_drv_init()
{
platform_driver_register(&myplatform_driver);
return 0;
}
static void __exit platform_drv_exit()
{
platform_driver_unregister(&myplatform_driver);
}


module_init(platform_drv_init);
module_exit(platform_drv_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Liwenzou");

测试: tree /sys/bus/platform/可以查看下采用platform的设备

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值