#define platform_get_drvdata(_dev) dev_get_drvdata(&(_dev)->dev)
void *dev_get_drvdata(const struct device *dev)
{
if (dev && dev->p)
return dev->p->driver_data;
return NULL;
}
上面是platform_get_drvdata(_dev)宏的代码
要想看明白这个宏的作用,需要先了解内核中和平台总线相关的几个结构体。
第一个平台总线的设备结构体,主要关注里面struct device dev;这个变量及其对应的结构体
struct platform_device {
const char * name;
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 device_private *p;这个变量,及其类型
struct device {
struct device *parent;
struct device_private *p;
struct kobject kobj;
const char *init_name; /* initial name of the device */
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;
#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;
#ifdef CONFIG_OF
struct device_node *of_node;
#endif
dev_t devt; /* dev_t, creates the sysfs "dev" */
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 device *device; //这个指针通常指向包含这个私有设备结构体的一个结构体。比如上面的第二个结构体。
这里我们主要关注的是void *driver_data;这个指针。从名字上可以看到,它时一个设备私有的数据,是传给其驱动使用数据。
struct device_private {
struct klist klist_children;
struct klist_node knode_parent;
struct klist_node knode_driver;
struct klist_node knode_bus;
void *driver_data;
struct device *device;
};
数据部分只要在注册设备时填充,最终通过平台设备的设备名称和驱动配上,驱动部分使用设备部分传过来的驱动数据即可进行相关硬件的动态初始化。
仔细观察的小伙伴们可能发现了,struct device结构体中也有一个类似的平台数据指针。用来存放平台相关的初始化数据。
void *platform_data;
使用void * 可以让数据类型存在多种可能,即满足不同设备驱动的数据都能通过指针传参。
等我学完平台总线设备驱动,再统一总结一个平台总线相关的驱动案例。
总结一下:
platform_get_drvdata(_dev) 即为通过传入struct platform_device结构体类型的指针,得到设备传给驱动的数据。
这样做主要是为了驱动数据和驱动操作分离。这样可以尽可能的让一个驱动程序,被多个驱动设备所使用。