platform总线学习与理解

内核已经实现了platform总线,我们只需了解总线所管理匹配的设备和驱动
对象及匹配规则,就可方便的来管理我们的设备对象和驱动对象。

1. 涉及的头文件

#include <linux/platform_device.h>


2. 了解platform总线的match规则及管理匹配的设备和驱动对象的类型

struct bus_type platform_bus_type = {
    .name        = "platform",
    .dev_attrs    = platform_dev_attrs,
    .match        = platform_match,
    .uevent        = platform_uevent,
    .pm        = &platform_dev_pm_ops,
};

3.匹配规则

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);

	/* When driver_override is set, only bind to the matching driver */
	if (pdev->driver_override)
		return !strcmp(pdev->driver_override, drv->name);

    //匹配设备树
	/* 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;

    //注意,id_table中 后边要有一个哨兵
	/* 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);
}

4.与platform总线所关联的设备对象为

struct platform_device {
	const char	*name;            //设备的名字 --> /sys/bus/platform/devices/
	int		id;                   //设备的id号,如果多个name相同,那么id必须不一样
	bool		id_auto;
	struct device	dev;          //驱动模型的基本设备类型
	u32		num_resources;
	struct resource	*resource;    //用于指向一个数组,数组元素个数决定于num_resources

	const struct platform_device_id	*id_entry;
	char *driver_override; /* Driver name to force a match */

	/* MFD cell pointer */
	struct mfd_cell *mfd_cell;

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

5. 与platform总线关联的驱动对象为

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;
	bool prevent_deferred_probe;
};

device结构体

kernel/include/linux/device.h
/**
 * struct device - The basic device structure
 * @parent:	The device's "parent" device, the device to which it is attached.
 * 		In most cases, a parent device is some sort of bus or host
 * 		controller. If parent is NULL, the device, is a top-level device,
 * 		which is not usually what you want.
 * @p:		Holds the private data of the driver core portions of the device.
 * 		See the comment of the struct device_private for detail.
 * @kobj:	A top-level, abstract class from which other classes are derived.
 * @init_name:	Initial name of the device.
 * @type:	The type of device.
 * 		This identifies the device type and carries type-specific
 * 		information.
 * @mutex:	Mutex to synchronize calls to its driver.
 * @bus:	Type of bus device is on.
 * @driver:	Which driver has allocated this
 * @platform_data: Platform data specific to the device.
 * 		Example: For devices on custom boards, as typical of embedded
 * 		and SOC based hardware, Linux often uses platform_data to point
 * 		to board-specific structures describing devices and how they
 * 		are wired.  That can include what ports are available, chip
 * 		variants, which GPIO pins act in what additional roles, and so
 * 		on.  This shrinks the "Board Support Packages" (BSPs) and
 * 		minimizes board-specific #ifdefs in drivers.
 * @driver_data: Private pointer for driver specific info.
 * @power:	For device power management.
 * 		See Documentation/power/devices.txt for details.
 * @pm_domain:	Provide callbacks that are executed during system suspend,
 * 		hibernation, system resume and during runtime PM transitions
 * 		along with subsystem-level and driver-level callbacks.
 * @pins:	For device pin management.
 *		See Documentation/pinctrl.txt for details.
 * @msi_list:	Hosts MSI descriptors
 * @msi_domain: The generic MSI domain this device is using.
 * @numa_node:	NUMA node this device is close to.
 * @dma_mask:	Dma mask (if dma'ble device).
 * @coherent_dma_mask: Like dma_mask, but for alloc_coherent mapping as not all
 * 		hardware supports 64-bit addresses for consistent allocations
 * 		such descriptors.
 * @dma_pfn_offset: offset of DMA memory range relatively of RAM
 * @dma_parms:	A low level driver may set these to teach IOMMU code about
 * 		segment limitations.
 * @dma_pools:	Dma pools (if dma'ble device).
 * @dma_mem:	Internal for coherent mem override.
 * @cma_area:	Contiguous memory area for dma allocations
 * @archdata:	For arch-specific additions.
 * @of_node:	Associated device tree node.
 * @fwnode:	Associated device node supplied by platform firmware.
 * @devt:	For creating the sysfs "dev".
 * @id:		device instance
 * @devres_lock: Spinlock to protect the resource of the device.
 * @devres_head: The resources list of the device.
 * @knode_class: The node used to add the device to the class list.
 * @class:	The class of the device.
 * @groups:	Optional attribute groups.
 * @release:	Callback to free the device after all references have
 * 		gone away. This should be set by the allocator of the
 * 		device (i.e. the bus driver that discovered the device).
 * @iommu_group: IOMMU group the device belongs to.
 *
 * @offline_disabled: If set, the device is permanently online.
 * @offline:	Set after successful invocation of bus type's .offline().
 *
 * At the lowest level, every device in a Linux system is represented by an
 * instance of struct device. The device structure contains the information
 * that the device model core needs to model the system. Most subsystems,
 * however, track additional information about the devices they host. As a
 * result, it is rare for devices to be represented by bare device structures;
 * instead, that structure, like kobject structures, is usually embedded within
 * a higher-level representation of the device.
 */
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 */
	void		*driver_data;	/* Driver data, set and get with
					   dev_set/get_drvdata */
	struct dev_pm_info	power;
	struct dev_pm_domain	*pm_domain;

#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
	struct irq_domain	*msi_domain;
#endif
#ifdef CONFIG_PINCTRL
	struct dev_pin_info	*pins;
#endif
#ifdef CONFIG_GENERIC_MSI_IRQ
	struct list_head	msi_list;
#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. */
	unsigned long	dma_pfn_offset;

	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_DMA_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 */
                        //kernel/include/linux/of.h
				struct device_node {
						const char *name;
						const char *type;
						phandle phandle;      
						char    *full_name;   

						struct  property *properties;  
						struct  property *deadprops;    /* removed properties */
						struct  device_node *parent;   
						struct  device_node *child;    
						struct  device_node *sibling;  
						struct  device_node *next;      /* next device of same type */ 
						struct  device_node *allnext;   /* next in list of all nodes */
						struct  proc_dir_entry *pde;    /* this node's proc directory */                                                                                                                                                                    
						struct  kref kref;    
						unsigned long _flags; 
						void    *data;        
				#if defined(CONFIG_SPARC)     
						char    *path_component_name;  
						unsigned int unique_id;        
						struct of_irq_controller *irq_trans;                                                                                                                                                                                                
				#endif 
				};


	struct fwnode_handle	*fwnode; /* firmware 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;

	bool			offline_disabled:1;
	bool			offline:1;
}; 

device_driver结构体

/**
  * struct device_driver - The basic device driver structure
  * @name:	Name of the device driver.
  * @bus:	The bus which the device of this driver belongs to.
  * @owner:	The module owner.
  * @mod_name:	Used for built-in modules.
  * @suppress_bind_attrs: Disables bind/unbind via sysfs.
  * @probe_type:	Type of the probe (synchronous or asynchronous) to use.
  * @of_match_table: The open firmware table.
  * @acpi_match_table: The ACPI match table.
  * @probe:	Called to query the existence of a specific device,
  *		whether this driver can work with it, and bind the driver
  *		to a specific device.
  * @remove:	Called when the device is removed from the system to
  *		unbind a device from this driver.
  * @shutdown:	Called at shut-down time to quiesce the device.
  * @suspend:	Called to put the device to sleep mode. Usually to a
  *		low power state.
  * @resume:	Called to bring a device from sleep mode.
  * @groups:	Default attributes that get created by the driver core
  *		automatically.
  * @pm:		Power management operations of the device which matched
  *		this driver.
  * @p:		Driver core's private data, no one other than the driver
  *		core can touch this.
  *
  * The device driver-model tracks all of the drivers known to the system.
  * The main reason for this tracking is to enable the driver core to match
  * up drivers with new devices. Once drivers are known objects within the
  * system, however, a number of other things become possible. Device drivers
  * can export information and configuration variables that are independent
  * of any specific device.
  */
 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 */
 	enum probe_type probe_type;
 
 	const struct of_device_id	*of_match_table;
                //用于匹配设备树
				kernel/include/linux/mod_devicetable.h
				struct of_device_id
				{       
						char    name[32];       
						char    type[32];
						char    compatible[128];
				#ifdef __KERNEL__
						void    *data;
				#else   
						kernel_ulong_t data;
				#endif  
				};

	const struct acpi_device_id	*acpi_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;
 };

设备树的调用过程:

static int platform_match(struct device *dev, struct device_driver *drv)
    of_driver_match_device(dev, drv)       //platform.c  
         of_match_device(drv->of_match_table, dev)    //of_device.h
            of_match_node(matches, dev->of_node)            //device.c

kernel/drivers/of/base.c
//下面是匹配设备树节点
/**    
 * of_match_node - Tell if an device_node has a matching of_match structure
 *      @matches:       array of of device match structures to search in
 *      @node:          the of device structure to match against
 *
 *      Low level utility function used by device matching.
 */    
const struct of_device_id *of_match_node(const struct of_device_id *matches,
                                         const struct device_node *node)
{
        if (!matches)         
                return NULL;  

        while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
                int match = 1;
                if (matches->name[0])          
                        match &= node->name            
                                && !strcmp(matches->name, node->name);
                if (matches->type[0])          
                        match &= node->type            
                                && !strcmp(matches->type, node->type);
                if (matches->compatible[0])    
                        match &= of_device_is_compatible(node,
                                                matches->compatible);          
                if (match)    
                        return matches;                
                matches++;
        }
        return NULL;
}
EXPORT_SYMBOL(of_match_node);       

设备树的信息会在系统的/sys/firmware/devicetree/base/        目录中

 

如背光的:

这里的所有属性都与对应的设备树文件一一对应,参数可以查看。

 

匹配设备树:

通过id_table匹配

 platform_driver->id_table->name  = id->name

platform_device->name = pdev->name

通过名字匹配:

 

总结:

一,匹配顺序

1、设备树的匹配
2、/* Then try ACPI style match */  没搞明白
3、匹配id_table
4、匹配 platform_device->name    和 device_driver->name

二,调用关系

1、设备树的匹配:
 

of_driver_match_device(struct device *dev,const struct device_driver *drv)
	of_match_device(const struct of_device_id *matches,const struct device *dev)	return of_match_device(drv->of_match_table, dev) != NULL;
		of_match_node(matches, dev->of_node);		//return (of_device_id)type
			__of_match_node(matches, node);		//return (of_device_id)type
				for (; matches->name[0] || matches->type[0] || matches->compatible[0]; matches++) {
					score = __of_device_is_compatible(node, matches->compatible,
									  matches->type, matches->name);
					if (score > best_score) {
						best_match = matches;
						best_score = score;
					}
				}

2、/* Then try ACPI style match */  没搞明白

3、匹配id_table
if (pdrv->id_table)
    platform_match_id(pdrv->id_table, pdev) != NULL;
    platform_device_id *platform_match_id(const struct platform_device_id *id,struct platform_device *pdev)
        if (strcmp(pdev->name, id->name) == 0)

4、匹配 platform_device->name    和 device_driver->name

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值