1、平台总线模型
平台总线模型是Linux系统虚拟出来的总线,而I2C、SPI等物理总线是真实存在的。
 平台总线模型将一个驱动分成两个部分,分别是device.c和driver.c,分别用来描述硬件信息和控制硬件。
 平台总线通过字符串比较,将name相同的device.c和driver.c匹配到一起来控制硬件。
 
平台总线模型的优点:
- 减少编写重复代码,提高效率
- 提高代码的利用率
2、platform device
//\Linux-4.9.88\include\linux\platform_device.h
struct platform_device {const char	*name;//设备名int		id; //设备ID号bool		id_auto;struct device	dev; //包含一个具体的device结构体u32		num_resources; //资源的数量struct resource	*resource; //用来保存硬件资源的结构体    io资源,中断资源,内存资源const struct platform_device_id	*id_entry; //平台设备的idchar *driver_override; /* Driver name to force a match *//* MFD cell pointer */struct mfd_cell *mfd_cell; //用户多功能卡,多功能设备的实现/* arch specific additions */struct pdev_archdata	archdata;
};
extern int platform_device_register(struct platform_device *); //注册平台总线设备
extern void platform_device_unregister(struct platform_device *);//删除平台总线设备2.1、struct 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 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 */
#endifu64		*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;
};3、platform driver
这个结构体包含了平台驱动需要实现的相关函数操作
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; //内嵌了一个设备驱动结构体/*平台设备ID,这与platform_device中的struct platform_device_id *id_entry是相同的主要是完成总线的匹配操作,platform总线的匹配操作第一匹配要素就是该元素。而不再是简单的name选项*/const struct platform_device_id *id_table;bool prevent_deferred_probe;
};
3.1、 struct device_driver
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;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;
};
4、实验demo
4.1 platform_device.c
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/platform_device.h>//static struct resource  * res;static void platform_dev_release(struct device *dev)
{printk("this is a test for platform_device\n");
} static struct resource platform_dev_resource[] = {};struct platform_device platform_dev_test = {.name = "100ask_test",.num_resources = ARRAY_SIZE(platform_dev_resource),.id = -1,.resource = platform_dev_resource,.dev = {.release = platform_dev_release,},
};static int __init platform_dev_test_init(void)
{int err;err = platform_device_register(&platform_dev_test);   return 0;
}static void __exit platform_dev_test_exit(void)
{platform_device_unregister(&platform_dev_test);}module_init(platform_dev_test_init);
module_exit(platform_dev_test_exit);MODULE_LICENSE("GPL");4.2 platform_driver.c
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/platform_device.h>static int platform_drv_probe(struct platform_device *pdev)
{printk("this is a test for platform_drv\n");return 0;}static int platform_drv_remove(struct platform_device *pdev)
{printk("this is in platform_drv_remove\n");return 0;
}static struct platform_driver platform_drv_test = {.probe      = platform_drv_probe,.remove     = platform_drv_remove,.driver     = {.name   = "100ask_test",},
};static int __init platform_drv_test_init(void)
{int err;err = platform_driver_register(&platform_drv_test); return 0;
}static void __exit platform_drv_test_exit(void)
{platform_driver_unregister(&platform_drv_test);
}module_init(platform_drv_test_init);
module_exit(platform_drv_test_exit);MODULE_LICENSE("GPL");4.3 Makefile
# 1. 使用不同的开发板内核时, 一定要修改KERN_DIR
# 2. KERN_DIR中的内核要事先配置、编译, 为了能编译内核, 要先设置下列环境变量:
# 2.1 ARCH,          比如: export ARCH=arm64
# 2.2 CROSS_COMPILE, 比如: export CROSS_COMPILE=aarch64-linux-gnu-
# 2.3 PATH,          比如: export PATH=$PATH:/home/book/100ask_roc-rk3399-pc/ToolChain-6.3.1/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin 
# 注意: 不同的开发板不同的编译器上述3个环境变量不一定相同,
#       请参考各开发板的高级用户使用手册KERN_DIR = /home/johan/share/linux_bsp/100ask_imx6ull-sdk/Linux-4.9.88all:make -C $(KERN_DIR) M=`pwd` modules clean:make -C $(KERN_DIR) M=`pwd` modules clean# 参考内核源码drivers/char/ipmi/Makefile
# 要想把a.c, b.c编译成ab.ko, 可以这样指定:
# ab-y := a.o b.o
# obj-m += ab.o#编译成ko
platform_dev-y := platform_device.o
platform_drv-y := platform_driver.o
obj-m	+= platform_dev.o
obj-m	+= platform_drv.o
4.4 板子上测试
 加载驱动
 
 匹配成功,调用prode函数
 
5、总结
总的来说,主要是填充两个结构体,struct platform_device和struct platform_driver