Linux提出了platform bus(平台总线)的概念,即使用虚拟总线将设备信息和驱动程序进行分离,设备树的提出就是进一步深化这种思想,将设备信息进行更好的整理。
设备被注册到总线上,总线会根据其名字搜索对应的驱动,如果找到将设备信息导入驱动程序并执行驱动;当一个驱动被注册到平台总线的时候,总线也会搜索设备。
设备信息--硬件信息/软件信息
硬件:地址资源,中断资源 struct resource
软件:网卡设备中的MAC地址等,这些信息需要私有数据的形式封装设备对象(一个设备的设备信息是一个对象,一个设备的驱动方法也是一个对象),需要我们自定义结构进行封装。
struct platform_device
id 表示这个platform_device对象表征了几个设备,当多个设备有共用资源的时候(MFD),里面填充相应的设备数量,如果只是一个,填-1
dev 父类对象,我们通常关心里面的platform_data和release,前者是用来存储私有设备信息的,后者是供当这个设备的最后引用被删除时被内核回调
定义好了platform_device 结构体后就可以调用函数 platform_add_devices 或platform_device_register向系统中注册设备,前者可以一次性注册多个平台设备。要注意的是,这里的 platform_device 设备的注册过程必须在相应设备驱动加载之前被调用,即执行注册之前。因为驱动注册时需要匹配内核中所以已注册的设备名。
设备被注册到总线上,总线会根据其名字搜索对应的驱动,如果找到将设备信息导入驱动程序并执行驱动;当一个驱动被注册到平台总线的时候,总线也会搜索设备。
//linux-3.4\include\linux\device.h
struct but_type{
const char *name;
const char *dev_name;
struct device *dev_root;
...
int (*match)(struct device *dev, struct device_driver *drv);
int (*probe)(struct device *dev);
int (*remove)(struct device *dev);
void (*shutdown)(struct device *dev);
...
const struct dev_pm_ops *pm;
}
//linux-3.4\drivers\base\platform.c
struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};
/**
* 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);
}
设备信息--硬件信息/软件信息
硬件:地址资源,中断资源 struct resource
软件:网卡设备中的MAC地址等,这些信息需要私有数据的形式封装设备对象(一个设备的设备信息是一个对象,一个设备的驱动方法也是一个对象),需要我们自定义结构进行封装。
struct platform_device
id 表示这个platform_device对象表征了几个设备,当多个设备有共用资源的时候(MFD),里面填充相应的设备数量,如果只是一个,填-1
dev 父类对象,我们通常关心里面的platform_data和release,前者是用来存储私有设备信息的,后者是供当这个设备的最后引用被删除时被内核回调
定义好了platform_device 结构体后就可以调用函数 platform_add_devices 或platform_device_register向系统中注册设备,前者可以一次性注册多个平台设备。要注意的是,这里的 platform_device 设备的注册过程必须在相应设备驱动加载之前被调用,即执行注册之前。因为驱动注册时需要匹配内核中所以已注册的设备名。
在内核初始化时do_basic_setup()->driver_init()->platform_bus_init()初始化platform bus(虚拟总线),设备注册的时候platform_device_register()->platform_device_add()内核把设备挂在虚拟的platform bus下,驱动注册的时候 platform_driver_register()->driver_register()->bus_add_driver()->driver_attach()->bus_for_each_dev() 对每个挂在虚拟的platform bus的设备作 __driver_attach()->driver_match_device()
{return drv->bus->match ? drv->bus->match(dev, drv) : 1;}
driver_probe_device()->really_probe(),如果相符就调用ret = drv->probe(dev);,如果probe成功则绑定该设备到该驱动。
platform_device.h
struct platform_device {
const char * name;
int id;
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;
};
ioport.h
struct resource {
resource_size_t start;
resource_size_t end;
const char *name;
unsigned long flags;
struct resource *parent, *sibling, *child;
};
device.h
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_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 */
/* arch specific additions */
struct dev_archdata archdata;
struct device_node *of_node; /* associated device tree 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);
};
platform_device.h
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;
};
device.h
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;
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;
};