我读了一些关于这个主题的文章。但他们都没有描述细节。
我所知道的是:
在设备树中声明"兼容" 属性:
gpio0: gpio@44e07000 {
compatible = "ti,omap4-gpio";
...
};
并通过
建立与平台驱动程序的连接static const struct of_device_id omap_gpio_match[] = {
{
.compatible = "ti,omap4-gpio",
},
{ },
};
...
static struct platform_driver omap_gpio_driver = {
.probe = omap_gpio_probe,
.driver = {
.name = "omap_gpio",
.pm = &gpio_pm_ops,
.of_match_table = of_match_ptr(omap_gpio_match),
},
};
因此, of_match_table 将用于匹配设备树中声明的兼容属性。
以及在 platform_match (drivers/base/platform.c
)函数中执行的匹配操作。我对此表示怀疑,因为我强调了 of_match_table 的引用,以及位于 of_device_get_match_data (drivers/of/device.c
)函数中的唯一可能结果。
~/wk/linux$ find . -name '*.c' | xargs grep '\<of_match_table\>' | grep -v -E 'of_match_table\s+='
./drivers/dma/sirf-dma.c: (of_match_device(op->dev.driver->of_match_table,
./drivers/macintosh/macio_asic.c: const struct of_device_id * matches = drv->of_match_table;
./drivers/macintosh/macio_asic.c: match = of_match_device(drv->driver.of_match_table, dev);
./drivers/nvmem/mxs-ocotp.c: match = of_match_device(dev->driver->of_match_table, dev);
./drivers/reset/sti/reset-syscfg.c: match = of_match_device(dev->driver->of_match_table, dev);
./drivers/mtd/devices/m25p80.c: * matching for .of_match_table
./drivers/soc/rockchip/pm_domains.c: match = of_match_device(dev->driver->of_match_table, dev);
./drivers/phy/phy-rockchip-usb.c: match = of_match_device(dev->driver->of_match_table, dev);
./drivers/acpi/bus.c: * @of_match_table: List of device IDs to match against.
./drivers/acpi/bus.c: const struct of_device_id *of_match_table)
./drivers/acpi/bus.c: if (!of_match_table || !of_compatible)
./drivers/acpi/bus.c: for (id = of_match_table; id->compatible[0]; id++)
./drivers/acpi/bus.c: drv->of_match_table);
./drivers/acpi/bus.c: drv->acpi_match_table, drv->of_match_table);
./drivers/pci/host/pcie-hisi.c: match = of_match_device(driver->of_match_table, &pdev->dev);
./drivers/pinctrl/stm32/pinctrl-stm32.c: match = of_match_device(dev->driver->of_match_table, dev);
./drivers/of/device.c: match = of_match_device(dev->driver->of_match_table, dev);
./drivers/mfd/axp20x.c: of_id = of_match_device(dev->driver->of_match_table, dev);
./drivers/gpu/drm/armada/armada_crtc.c: match = of_match_device(dev->driver->of_match_table, dev);
./arch/powerpc/kernel/ibmebus.c: ibmebus_create_devices(drv->driver.of_match_table);
./arch/powerpc/kernel/ibmebus.c: const struct of_device_id *matches = drv->of_match_table;
./sound/soc/qcom/lpass-cpu.c: match = of_match_device(dev->driver->of_match_table, dev);
但是这个功能并没有用在一些常见的模块中。
~/wk/linux$ find . -name '*.c' | xargs grep of_device_get_match_data
./drivers/dma/sh/shdmac.c: pdata = of_device_get_match_data(&pdev->dev);
./drivers/dma/tegra210-adma.c: cdata = of_device_get_match_data(&pdev->dev);
./drivers/dma/tegra20-apb-dma.c: cdata = of_device_get_match_data(&pdev->dev);
./drivers/usb/host/xhci-tegra.c: tegra->soc = of_device_get_match_data(&pdev->dev);
./drivers/usb/phy/phy-msm-usb.c: pdata->phy_type = (enum msm_usb_phy_type)of_device_get_match_data(&pdev->dev);
./drivers/mtd/spi-nor/fsl-quadspi.c: q->devtype_data = of_device_get_match_data(dev);
./drivers/mtd/nand/qcom_nandc.c: dev_data = of_device_get_match_data(dev);
./drivers/mtd/nand/atmel_nand.c: of_device_get_match_data(host->dev);
./drivers/rtc/rtc-sunxi.c: chip->data_year = of_device_get_match_data(&pdev->dev);
./drivers/spi/spi-mpc512x-psc.c: mps->type = (int)of_device_get_match_data(dev);
./drivers/watchdog/mpc8xxx_wdt.c: wdt_type = of_device_get_match_data(&ofdev->dev);
./drivers/phy/phy-exynos-mipi-video.c: phy_dev = of_device_get_match_data(dev);
./drivers/phy/phy-sun4i-usb.c: data->cfg = of_device_get_match_data(dev);
./drivers/pci/host/pci-imx6.c: (enum imx6_pcie_variants)of_device_get_match_data(&pdev->dev);
./drivers/pci/host/pcie-qcom.c: pcie->ops = (struct qcom_pcie_ops *)of_device_get_match_data(dev);
./drivers/i2c/busses/i2c-rcar.c: priv->devtype = (enum rcar_i2c_type)of_device_get_match_data(dev);
./drivers/i2c/busses/i2c-tegra.c: i2c_dev->hw = of_device_get_match_data(&pdev->dev);
./drivers/tty/serial/imx.c: sport->devdata = of_device_get_match_data(&pdev->dev);
./drivers/gpio/gpio-mpc8xxx.c: of_device_get_match_data(&pdev->dev);
./drivers/gpio/gpio-tegra.c: config = of_device_get_match_data(&pdev->dev);
./drivers/clk/clk-palmas.c: match_data = of_device_get_match_data(&pdev->dev);
./drivers/input/misc/pmic8xxx-pwrkey.c: pwrkey->shutdown_fn = of_device_get_match_data(&pdev->dev);
./drivers/input/touchscreen/edt-ft5x06.c: chip_data = of_device_get_match_data(&client->dev);
./drivers/pinctrl/sh-pfc/core.c: info = of_device_get_match_data(&pdev->dev);
./drivers/thermal/rcar_thermal.c: unsigned long of_data = (unsigned long)of_device_get_match_data(dev);
./drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c: data = of_device_get_match_data(&pdev->dev);
./drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c: data = of_device_get_match_data(&pdev->dev);
./drivers/net/ethernet/renesas/sh_eth.c: mdp->cd = (struct sh_eth_cpu_data *)of_device_get_match_data(&pdev->dev);
./drivers/net/ethernet/renesas/ravb_main.c: chip_id = (enum ravb_chip_id)of_device_get_match_data(&pdev->dev);
./drivers/of/device.c:const void *of_device_get_match_data(const struct device *dev)
./drivers/of/device.c:EXPORT_SYMBOL(of_device_get_match_data);
./drivers/gpu/drm/nouveau/nouveau_platform.c: func = of_device_get_match_data(&pdev->dev);
./drivers/gpu/drm/exynos/exynos_drm_rotator.c: of_device_get_match_data(dev);
./drivers/gpu/drm/exynos/exynos_mixer.c: drv = of_device_get_match_data(dev);
./drivers/gpu/drm/exynos/exynos5433_drm_decon.c: ctx->out_type = (unsigned long)of_device_get_match_data(dev);
./drivers/gpu/drm/exynos/exynos_drm_fimd.c: ctx->driver_data = of_device_get_match_data(dev);
./drivers/gpu/drm/exynos/exynos_hdmi.c: hdata->drv_data = of_device_get_match_data(dev);
./drivers/gpu/drm/exynos/exynos_drm_dsi.c: dsi->driver_data = of_device_get_match_data(dev);
./drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c: dc_ops = (struct kirin_dc_ops *)of_device_get_match_data(dev);
./drivers/gpu/drm/msm/hdmi/hdmi_phy.c: phy->cfg = (struct hdmi_phy_cfg *)of_device_get_match_data(dev);
./drivers/gpu/drm/msm/hdmi/hdmi.c: of_device_get_match_data(dev);
./drivers/gpu/drm/msm/msm_drv.c: return (int) (unsigned long) of_device_get_match_data(dev);
./drivers/gpu/drm/rockchip/rockchip_drm_vop.c: vop_data = of_device_get_match_data(dev);
./sound/soc/sh/rcar/core.c: priv->flags = (unsigned long)of_device_get_match_data(dev);
./sound/soc/sh/rcar/rsrc-card.c: of_data = of_device_get_match_data(dev);
./sound/soc/sh/rcar/rsrc-card.c: const struct rsrc_card_of_data *of_data = of_device_get_match_data(dev);
任何人都可以提供一些有用的信息吗?
答案 0 :(得分:5)
您的问题的规范答案可以在LWN找到:Platform Devices and Device Trees。您需要的是使用它的正确指导。 A Tutorial on the Device Tree是一本合理的教学指南。有关背景知识,请阅读Linux and the Device Tree。此外,elinux.org还有一些应该提供帮助的wiki,例如Device Tree Linux和Device Tree Usage以及Device Tree Reference。
答案 1 :(得分:1)
在驱动程序的探测功能中必须是/必须是这一行:
probe(struct bus_client *client,
const struct bus_device_id *id)
{
const struct of_device_id *match;
match = of_match_device(omap_gpio_match);
if (!match)
return -ENODEV;
else
//write the driver stuff for Probe
这是设备树与驱动程序链接的方式。 omap_gpio_match您已经与设备树中定义的“兼容ID”链接,以及驱动程序如何与设备树链接。
答案 2 :(得分:0)
注册平台驱动程序时,将使用driver.bus
回调初始化platform_bus_type
:
int __platform_driver_register(struct platform_driver *drv,
struct module *owner)
{
drv->driver.owner = owner;
drv->driver.bus = &platform_bus_type;
这些回调之一是platform_match
:
struct bus_type platform_bus_type = {
.name = "platform",
.dev_groups = platform_dev_groups,
.match = platform_match,
此回调用于将驱动程序以设备树样式绑定到设备(如果存在):
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;
/* 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);
}