内核小碎碎-第五集 platform_device 与 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;
	const struct platform_device_id *id_table;
	bool prevent_deferred_probe;
};

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;
	void (*coredump) (struct device *dev);

	struct driver_private *p;
};


struct bus_type {
	const char		*name;
	const char		*dev_name;
	struct device		*dev_root;
	const struct attribute_group **bus_groups;
	const struct attribute_group **dev_groups;
	const struct attribute_group **drv_groups;

	int (*match)(struct device *dev, struct device_driver *drv);
	int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
	int (*probe)(struct device *dev);
	int (*remove)(struct device *dev);
	void (*shutdown)(struct device *dev);

	int (*online)(struct device *dev);
	int (*offline)(struct device *dev);

	int (*suspend)(struct device *dev, pm_message_t state);
	int (*resume)(struct device *dev);

	int (*num_vf)(struct device *dev);

	int (*dma_configure)(struct device *dev);

	const struct dev_pm_ops *pm;

	const struct iommu_ops *iommu_ops;

	struct subsys_private *p;
	struct lock_class_key lock_key;

	bool need_parent_lock;
};

#define platform_driver_register(drv) \
	__platform_driver_register(drv, THIS_MODULE)
	
int __platform_driver_register(struct platform_driver *drv,
				struct module *owner)
{
	drv->driver.owner = owner;
	drv->driver.bus = &platform_bus_type;
	drv->driver.probe = platform_drv_probe;
	drv->driver.remove = platform_drv_remove;
	drv->driver.shutdown = platform_drv_shutdown;

	return driver_register(&drv->driver);
}

//一种是由设备树展开得到;一种是由arch/arm/mach-xxx/文件中定义;内核移植时完善之
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;//平台设备ID表,同系列微差别设备区分
	char *driver_override; /* Driver name to force a match */

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

	/* arch specific additions */
	struct pdev_archdata	archdata;//架构相关、预留
};

int platform_device_register(struct platform_device *pdev)
{
	device_initialize(&pdev->dev);
	arch_setup_pdev_archdata(pdev);
	return platform_device_add(pdev);
}

/**
 * platform_match - bind platform device to platform driver.
 * @dev: device.
 * @drv: driver.
 *
 * Platform device IDs are assumed to be encoded like this:
 * "<name><instance>", where <name> is a short description of the type of
 * device, like "pci" or "floppy", and <instance> is the enumerated
 * instance of the device, like '0' or '42'.  Driver IDs are simply
 * "<name>".  So, extract the <name> from the platform_device structure,
 * and compare it against the name of the driver. Return whether they match
 * or not.
 */
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 */
	//首先按设备树去匹配见下文@1分析
	if (of_driver_match_device(dev, drv))
		return 1;

	/* Then try ACPI style match */
	if (acpi_driver_match_device(dev, drv))
		return 1;

	/* Then try to match against the id table */
	//驱动可能支持多个设备,来的设备和其id_table中的name字段匹配,命中其中一个则匹配上
	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);
}

i2c总线,PCI总线以及us
b总线,这些物理总线
platform总线是虚拟的,为了内核以总线方式统一管理

@1:

//驱动和设备分离  驱动是业务处理,算法之类,数据在设备包含。
//举例 
static const struct of_device_id davinci_i2s_match[] = {
	{ .compatible = "ti,da850-mcbsp" },
	{},
};
MODULE_DEVICE_TABLE(of, davinci_i2s_match);

static struct platform_driver davinci_mcbsp_driver = {
	.probe		= davinci_i2s_probe,
	.remove		= davinci_i2s_remove,
	.driver		= {
		.name	= "davinci-mcbsp",//可用其在内核中找对应的platform_device代码
		.of_match_table = of_match_ptr(davinci_i2s_match),
	},
};
static inline int of_driver_match_device(struct device *dev,
					 const struct device_driver *drv)
{
	//传入包含compatible 字段的of_device_id  davinci_i2s_match
	return of_match_device(drv->of_match_table, dev) != NULL;
}
const struct of_device_id *of_match_device(const struct of_device_id *matches,
					   const struct device *dev)
{
	if ((!matches) || (!dev->of_node))
		return NULL;
		//设备树节点dev->of_node ,将来查找其compatible属性值以及name和type值用于和of_device_id 匹配
	return of_match_node(matches, dev->of_node);
}
static struct platform_device dm355_asp1_device = {
	.name		= "davinci-mcbsp",
	.id		= 1,
	.num_resources	= ARRAY_SIZE(dm355_asp1_resources),
	.resource	= dm355_asp1_resources,
};

使用时,1)在module_init中调用platform_driver_register注册davinci_mcbsp_driver这个platform_driver,在module_exit中调用platform_driver_unregister注销platform_driver。
2)实现platform_driver的probe和remove等函数,如将原来放在module_init中的初始化操作放在probe中,反初始化操作放在remove中
框架示例:
1)设备树文件:
vexpress-v2p-ca9.dts中添加设备

hello {
		compatible = "jxl,hello-test";
	};

2)驱动文件
hello_platform.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>

static int hello_probe(struct platform_device *pdev)
{

	printk(KERN_ALERT "hello probe completed.\n");

	return 0;
}

static int hello_remove(struct platform_device *pdev)
{
	printk(KERN_ALERT "hello remove completed.\n");

	return 0;
}


static const struct of_device_id hello_match[] = {
	{ .compatible = "jxl,hello-test", },
	{}
};

static struct platform_driver hello_driver = {
	.driver = {
		.name = "hello-test",
		.of_match_table = hello_match,
	},
	.probe	= hello_probe,
	.remove    = hello_remove,
};


static int  __init hello_init(void) {
	printk(KERN_ALERT "hello init completed.\n");
	platform_driver_register(&hello_driver);
	return 0;
}


static void __exit hello_exit(void) {
	printk(KERN_ALERT "hello exit now.\n");
	platform_driver_unregister(&hello_driver);
}


module_init(hello_init);
module_exit(hello_exit);

MODULE_AUTHOR("JACK <shaoyoujing@163.com>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("A simple hello driver show.");
MODULE_ALIAS("Hello Module");

3)编译设备树
make CROSS_COMPILE=arm-none-linux-gnueabi- ARCH=arm dtbs

编译驱动
make CROSS_COMPILE=arm-none-linux-gnueabi- ARCH=arm

Makefile如下:

obj-m:=hello_platform.o
	
CURRENT_PATH:=$(shell pwd)
	#the absolute path
LINUX_KERNEL_PATH:=/home/datou/qqq/linux-4.19.108/
	#complie object
modules:
	make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
clean:
	rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
.PHONY: modules clean
  1. 运行实验
出现hello设备
/ # ls /sys/devices/platform/
10000000.sysreg            Fixed MDIO bus.0
10013000.virtio_mmio       alarmtimer
10013200.virtio_mmio       hello
10013400.virtio_mmio       hsb@e0000000
10013600.virtio_mmio       oprofile-perf.0
10020000.clcd              pmu
1e000000.scu               power
1e000600.timer             reg-dummy
1e000620.watchdog          smb@4000000
1e00a000.cache-controller  uevent

安装驱动:注意输出
/ # insmod hello_platform.ko 
hello_platform: loading out-of-tree module taints kernel.
hello init completed.
hello probe completed.

查看设备:出现hello-test驱动
/ # ls /sys/bus/platform/drivers
ARM-CCI              of_fixed_clk         syscon
alarmtimer           of_fixed_factor_clk  versatile-i2c
armv7-pmu            oprofile-perf        vexpress-hwmon
basic-mmio-gpio      physmap-flash        vexpress-osc
generic-bl           pwrseq_emmc          vexpress-regulator
gpio-clk             pwrseq_simple        vexpress-reset
hello-test           reg-dummy            vexpress-syscfg
isp1760              reg-fixed-voltage    vexpress-sysreg
leds-gpio            sbsa-uart            virtio-mmio
mtd-ram              smc91x
of-flash             smsc911x

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值