平台总线和IIC,SPI,IIS都是总线类型,一般的,总线下,挂载对应的设备。但实际上,设备要正常运转,是需要驱动程序来未知提供驱动的。所以linux内核也把驱动挂载在对应的总线下。总线,驱动,设备三者缺一不可.
相应的,内核衍生出来的平台总线,那么便衍生出来了平台设备和凭条驱动。他们均有自己的专属函数来注册,注销。这个是成一套体系结构的.在以后的驱动开发中,很是常见与重要.
一)内核中的总线,设备,驱动
1)总线
struct bus_type {
const char *name;
const char *dev_name;
struct device *dev_root;
struct bus_attribute *bus_attrs;//总线属性
struct device_attribute *dev_attrs;//设备属性
struct driver_attribute *drv_attrs;//驱动属性
int (*match)(struct device *dev, struct device_driver *drv);//匹配总线下的设备和驱动
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);//用于总线环境变量的添加
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 dev_pm_ops *pm;//电源管理
struct iommu_ops *iommu_ops;
struct subsys_private *p;//将bus device sysfs联系起来
struct lock_class_key lock_key;
};
注册:bus_register(struct bus_type *bus);
注销:bus_unregister(struct bus_type *bus);
2)设备
struct device {
struct device *parent;
struct device_private *p;
struct kobject kobj;
const char *init_name; /* initial name of the device */
const struct device_type *type;
struct mutex mutex; /* mutex to synchronize calls to
* its driver.
*/
struct bus_type *bus; /* type of bus device is on 设备所属的总线*/
struct device_driver *driver; /* which driver has allocated this
device */
void *platform_data; /* Platform specific data, device
core doesn't touch it */
struct dev_pm_info power;
struct dev_pm_domain *pm_domain;
#ifdef CONFIG_PINCTRL
struct dev_pin_info *pins;
#endif
#ifdef CONFIG_NUMA
int numa_node; /* NUMA node this device is close to */
#endif
u64 *dma_mask; /* dma mask (if dma'able device) */
u64 coherent_dma_mask;/* Like dma_mask, but for
alloc_coherent mappings as
not all hardware supports
64 bit addresses for consistent
allocations such descriptors. */
struct device_dma_parameters *dma_parms;
struct list_head dma_pools; /* dma pools (if dma'ble) */
struct dma_coherent_mem *dma_mem; /* internal for coherent mem
override */
#ifdef CONFIG_CMA
struct cma *cma_area; /* contiguous memory area for dma
allocations */
#endif
/* arch specific additions */
struct dev_archdata archdata;
struct device_node *of_node; /* associated device tree node */
struct acpi_dev_node acpi_node; /* associated ACPI device node */
dev_t devt; /* dev_t, creates the sysfs "dev" */
u32 id; /* device instance */
spinlock_t devres_lock;
struct list_head devres_head;
struct klist_node knode_class;
struct class *class;
const struct attribute_group **groups; /* optional groups */
void (*release)(struct device *dev);
struct iommu_group *iommu_group;
};
设备注册:int device_register(struct device *dev)
设备注销:void device_unregister(struct device *dev)
3)设备驱动
struct device_driver {
const char *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 */
const struct of_device_id *of_match_table;
const struct acpi_device_id *acpi_match_table;
int (*probe) (struct device *dev);// 设备match到驱动,则调用对应驱动的probe函数,驱动设备
int (*remove) (struct device *dev);//当驱动或者设备被卸载,则调用对应驱动的remove函数
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;
};
驱动注册:int driver_register(struct device_driver *drv)
驱动注销:void driver_unregister(struct device_driver *drv)
二)平台设备总线
总线:
struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};
设备:
struct platform_device {
const char *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;
};
平台设备的注册:platform_device_register(struct platform_device * pdev)
平台设备的注销:platform_device_unregister(struct platform_device * pdev)
驱动:
struct platform_driver {
int (*probe)(struct platform_device *);
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;
const struct platform_device_id *id_table;
};
平台驱动的注册:int platform_driver_register(struct platform_driver *drv)
平台驱动的注销:void platform_driver_unregister(struct platform_driver *drv)
平台设备匹配的流程:
先插入一个函数,match
static int platform_match(struct device *dev, struct device_driver *drv)
{
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);
/* Attempt an OF style match first */
if (of_driver_match_device(dev, drv))
return 1;
/* Then try ACPI style match */
if (acpi_driver_match_device(dev, drv))
return 1;
/* Then try to match against the id table */
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;
/* fall-back to driver name match */
return (strcmp(pdev->name, drv->name) == 0);
}
//match 的方式:不同的内核,可能有所不同:我的内核版本:3.10.46
1.OF style match first
2.ACPI style match
3.match against the id table
4.driver name match
大概的匹配流程:
1)平台设备注册流程:
platform_device_register()
{
--->platform_device_add()
{
--->device_add()
{
--->device_add()
{
--->bus_probe_device()
{
--->device_attach()
{
--->bus_for_each_drv(dev->bus, NULL, dev, __device_attach)
{
--->__device_attach()
{
--->driver_match_device()//platform_match()
//当match到驱动后,继续下面步骤:
--->driver_probe_device()
{
--->really_probe()
{
--->drv->probe()//调用对应驱动的probe函数
}
}
}
}
}
}
}
}
}
}
2)平台驱动注册流程:
platform_driver_register()
{
--->driver_register()
{
--->bus_add_driver()
{
--->driver_attach()
{
--->bus_for_each_dev(drv->bus, NULL, drv, __driver_attach)
{
--->__driver_attach()
{
--->driver_match_device()//platform_match()
//当match到对应的设备后,继续
--->driver_probe_device()
{
--->really_probe()
{
--->drv->probe()//调用当前注册驱动的probe函数
}
}
}
}
}
}
}
}
1.设备向对应平台bus注册设备,设备挂载到平台bus下面的dev list链表中.
2.驱动向对应平台bus注册驱动,驱动挂载到平台bus下面的driver list链表中.
3.设备和对应总线下的driver list链表中每个driver进行匹配(match).匹配成功则调用对应driver的probe函数,否则匹配失败,则设备无法被驱动,设备无法工作.
match函数已经在上面列出。它有自己的匹配规则,上一篇的实例是按照match name来进行匹配的.
当设备或者驱动被卸载时,驱动的remove函数都会被调用.
平台设备总线的意义:移植性强。通过我们是不需要写平台设备文件的,只需要写对应的驱动文件。而驱动文件一般移植时并不需要修改。只需要修改对应的platform_data 平台数据和resource 平台资源列表便可.
这样修改一个驱动或者移植一个驱动到另一个内核便变得很简单。