Platform 设备驱动:platform

时间: 2023-07-09 admin IT培训

Platform 设备驱动:platform

Platform 设备驱动:platform

Linux version: 4.14

Code link: Linux source code (v4.14) - Bootlin


1 函数原型

(1) platform_get_drvdata  [ include/linux/platform_device.h: 211 ]

static inline void *platform_get_drvdata(const struct platform_device *pdev)
{return dev_get_drvdata(&pdev->dev);
}

 其中 dev_get_drvdata  [ include/linux/device.h: 1024 ]

static inline void *dev_get_drvdata(const struct device *dev)
{return dev->driver_data;
}

(2)platform_set_drvdata  [ include/linux/platform_device.h: 216 ]

static inline void platform_set_drvdata(struct platform_device *pdev,void *data)
{dev_set_drvdata(&pdev->dev, data);
}

 其中 dev_set_drvdata  [ include/linux/device.h: 1029 ]

static inline void dev_set_drvdata(struct device *dev, void *data)
{dev->driver_data = data;
}

2 涉及的变量类型

(1)platform_device  [ include/linux/platform_device.h: 23 ]

platform_device 是 platform设备结构体,主要关注里面 struct device dev;

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;char *driver_override; /* Driver name to force a match *//* MFD cell pointer */struct mfd_cell *mfd_cell;/* arch specific additions */struct pdev_archdata	archdata;
};

(2)device  [ include/linux/device.h: 888 ]

device 是一个通用的设备结构体,里面放的是每个设备都会有的通用数据。我们主要关注 void *platform_data; 这个变量。

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 thisdevice */void		*platform_data;	/* Platform specific data, devicecore doesn't touch it */void		*driver_data;	/* Driver data, set and get withdev_set/get_drvdata */struct dev_links_info	links;struct dev_pm_info	power;struct dev_pm_domain	*pm_domain;#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAINstruct irq_domain	*msi_domain;
#endif
#ifdef CONFIG_PINCTRLstruct dev_pin_info	*pins;
#endif
#ifdef CONFIG_GENERIC_MSI_IRQstruct list_head	msi_list;
#endif#ifdef CONFIG_NUMAint		numa_node;	/* NUMA node this device is close to */
#endifconst struct dma_map_ops *dma_ops;u64		*dma_mask;	/* dma mask (if dma'able device) */u64		coherent_dma_mask;/* Like dma_mask, but foralloc_coherent mappings asnot all hardware supports64 bit addresses for consistentallocations 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 memoverride */
#ifdef CONFIG_DMA_CMAstruct cma *cma_area;		/* contiguous memory area for dmaallocations */
#endif/* arch specific additions */struct dev_archdata	archdata;struct device_node	*of_node; /* associated device tree node */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;struct iommu_fwspec	*iommu_fwspec;bool			offline_disabled:1;bool			offline:1;bool			of_node_reused:1;
};

(3)void *platform_data

        platform_data 用来存放平台相关的初始化数据。使用 void * 可以让数据类型存在多种可能,即满足不同设备驱动的数据都能通过指针传参。其实这里是用来存放 platform_device 数据结构的,通过 platform_driver 和 platform_device 的名字进行匹配后,platform_driver 部分就可以使用platform_device 传过来的数据了。

小结:platform_get_drvdata 即为通过传入 struct platform_device 结构体类型的指针,得到设备传给驱动的数据。而 platform_set_drvdata 则将 platform_data 指向传入的数据。

3 应用例程

例如,对于DM9000网卡,为platform_data定义一个dm9000_plat_data结构体,定义完后,可以将MAC地址、总线宽度、板上有无EEPROM信息等放入platform_data中。

static struct dm9000_plat_data dm9000_platdata = {.flags = DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM,
};static struct platform_device dm9000_device = {.name = "dm9000",.id = 0,.num_resources = ARRAY_SIZE(dm9000_resource),.resource = dm9000_resource,.dev = {.platform_data = &dm9000_platdata, // 自定义设备数据}
};

在DM9000网卡驱动的probe()中,可这样拿到platform_data:

struct dm9000_plat_data *pdata = platform_get_drvdata(pdev);

 4 参考

深度讲解Linux设备驱动的软件架构 - 知乎 (zhihu.com)