How devices in device tree and platform drivers were connected - linux

I read some articles about this topic. but none of them describes the details.
What I know is:
declare "compatible" property in Device tree:
gpio0: gpio#44e07000 {
compatible = "ti,omap4-gpio";
...
};
and make the connection to platform driver by
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),
},
};
and as a result, of_match_table will be used to match the compatible property declared in Device Tree.
and the match action performed in platform_match (drivers/base/platform.c) function. I doubt this because the I greped reference of of_match_table and the only probable result located in of_device_get_match_data (drivers/of/device.c) function.
~/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);
But this function is not used in some common modules.
~/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);
anyone can give some useful information?

The canonical answer to your question can be found at LWN: Platform Devices and Device Trees. What you need is the proper guidance on using it. A Tutorial on the Device Tree is a reasonable instruction guide. For background, you should read about Linux and the Device Tree. Also, elinux.org has a few wikis that should help, like Device Tree Linux and Device Tree Usage and Device Tree Reference.

in the probe function of the driver there has to be/must be this line :
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
This is how the device tree is linked with your driver.
omap_gpio_match you have already linked with the "compatible id" which you have defined in the device tree and thats how driver has been linked with the device tree.

When you register your platform driver you initialize driver.bus with platform_bus_type callbacks:
int __platform_driver_register(struct platform_driver *drv, struct module *owner)
{
drv->driver.owner = owner;
drv->driver.bus = &platform_bus_type;
One of these callbacks is platform_match:
struct bus_type platform_bus_type = {
.name = "platform",
.dev_groups = platform_dev_groups,
.match = platform_match,
And this callback is used to bind driver to the device in device tree style if there is one:
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);
}

Related

Why am i Getting D-Bus argument type error?

I'm trying to invoke "Inhibit" method of org.gnome.SessionManager using D-Bus, but I'm getting no cookie in return and the following error:
Argument 0 is specified to be of type "uint32", but is actually of type "string"
But all types seems to be ok.
DBusConnection * dbus_conn = nullptr;
DBusError dbus_error;
DBusPendingCall *pending;
const char * szProgramName = "SEER";
const char * szReason = "just because";
dbus_uint32_t xid = 0;
dbus_uint32_t gflags = 0xc;
dbus_uint32_t cookie = 0;
// Initialize D-Bus error
dbus_error_init(&dbus_error);
dbus_conn = dbus_bus_get(DBUS_BUS_SYSTEM, &dbus_error);
DBusMessage * dbus_msg = nullptr;
DBusMessage * dbus_reply = nullptr;
if (dbus_error_is_set(&dbus_error))
{
fprintf(stderr, "Connection Error (%s)\n", dbus_error.message);
dbus_error_free(&dbus_error);
}
if (NULL == dbus_conn)
{
exit(1);
}
dbus_msg = dbus_message_new_method_call("org.gnome.SessionManager", "/org/gnome/SessionManager", "org.gnome.SessionManager", "Inhibit");
dbus_message_append_args(dbus_msg,
DBUS_TYPE_STRING, &szProgramName,
DBUS_TYPE_UINT32, &xid,
DBUS_TYPE_STRING, &szReason,
DBUS_TYPE_UINT32, &gflags,
DBUS_TYPE_INVALID);
dbus_connection_send_with_reply(dbus_conn, dbus_msg, &pending, -1);
dbus_pending_call_block(pending);
dbus_reply = dbus_pending_call_steal_reply(pending);
if (dbus_reply != NULL)
{
dbus_message_get_args(dbus_reply, &dbus_error,
DBUS_TYPE_UINT32, &cookie,
DBUS_TYPE_INVALID);
}
else
printf("dbus_reply is null\n");
printf("cookie %x error %s\n",cookie, dbus_error.message);
any help would be greatly appreciated!
EDIT
after changing dbus_message_get_args to
dbus_message_get_args(dbus_reply, &dbus_error,
DBUS_TYPE_STRING, &cookie,
DBUS_TYPE_INVALID);
Apparently cookie var holds
The name org.gnome.SessionManager was not provided by any .service files
and that's a different error entirely..
Consider replacing
dbus_conn = dbus_bus_get(DBUS_BUS_SYSTEM, &dbus_error);
with
dbus_conn = dbus_bus_get(DBUS_BUS_SESSION, &dbus_error);

In Rcpp, how to get a user-defined structure from C into R

Am using Rcpp packages and can get my C function to compile and run in R, but now I want to return a large, user-defined data structure to R. The fields in the structure are either numbers or strings - no new or odd types within the structure. The example below is simplified and doesn't compile, but it conveys the idea of my problem.
typedef struct {
char* firstname[128];
char* lastname[128];
int nbrOfSamples;
} HEADER_INFO;
// [[Rcpp::export]]
HEADER_INFO* read_header(Rcpp::StringVector strings) {
FILE *fp;
MEF_HEADER_INFO *header;
char * filename = (char*)(strings(0));
char * password = (char*)(strings(1));
header = (HEADER_INFO*)malloc(sizeof(HEADER_INFO));
memset(header, 0, sizeof(HEADER_INFO));
fp = fopen(filename, "r");
(void)read_header(header, password);
return header;
}
I'm pretty sure that I could package the entries in the header back into a StringVector, but that seems like a brute-force approach. My question is whether a more elegant solution exists. It is not clear to me what form such a structure would even have in R: a named List?
Thanks!
The right structure in R depends on what your struct looks like exactly. A named list is the most general one. Here a simple sample implementation for a wrap function as referred to in the comments:
#include <RcppCommon.h>
typedef struct {
char* firstname[128];
char* lastname[128];
int nbrOfSamples;
} HEADER_INFO;
namespace Rcpp {
template <>
SEXP wrap(const HEADER_INFO& x);
}
#include <Rcpp.h>
namespace Rcpp {
template <>
SEXP wrap(const HEADER_INFO& x) {
Rcpp::CharacterVector firstname(x.firstname, x.firstname + x.nbrOfSamples);
Rcpp::CharacterVector lastname(x.lastname, x.lastname + x.nbrOfSamples);
return Rcpp::wrap(Rcpp::List::create(Rcpp::Named("firstname") = firstname,
Rcpp::Named("lastname") = lastname,
Rcpp::Named("nbrOfSamples") = Rcpp::wrap(x.nbrOfSamples)));
};
}
// [[Rcpp::export]]
HEADER_INFO getHeaderInfo() {
HEADER_INFO header;
header.firstname[0] = (char*)"Albert";
header.lastname[0] = (char*)"Einstein";
header.firstname[1] = (char*)"Niels";
header.lastname[1] = (char*)"Bohr";
header.firstname[2] = (char*)"Werner";
header.lastname[2] = (char*)"Heisenberg";
header.nbrOfSamples = 3;
return header;
}
/*** R
getHeaderInfo()
*/
Output:
> getHeaderInfo()
$firstname
[1] "Albert" "Niels" "Werner"
$lastname
[1] "Einstein" "Bohr" "Heisenberg"
$nbrOfSamples
[1] 3
However, for this particular case a data.frame would be more natural to use, which can be achieved by replacing above wrap with:
template <>
SEXP wrap(const HEADER_INFO& x) {
Rcpp::CharacterVector firstname(x.firstname, x.firstname + x.nbrOfSamples);
Rcpp::CharacterVector lastname(x.lastname, x.lastname + x.nbrOfSamples);
return Rcpp::wrap(Rcpp::DataFrame::create(Rcpp::Named("firstname") = firstname,
Rcpp::Named("lastname") = lastname));
};
Output:
> getHeaderInfo()
firstname lastname
1 Albert Einstein
2 Niels Bohr
3 Werner Heisenberg

Difference between spi_driver.id_table and spi_driver.driver.of_match_table

I'm currently trying to understand how linux drivers work. As far as I know, A driver's probe/init function is called when the kernel parses the corresponding .compatible string in the device tree. However, in the arizona-spi driver it looks like there are multiple compatible strings referenced in different members:
static const struct spi_device_id arizona_spi_ids[] = {
{ "wm5102", WM5102 },
{ "wm5110", WM5110 },
{ },
};
MODULE_DEVICE_TABLE(spi, arizona_spi_ids);
static struct spi_driver arizona_spi_driver = {
.driver = {
.name = "arizona",
.owner = THIS_MODULE,
.pm = &arizona_pm_ops,
// Contains e.g. "wlf,wm5102"
.of_match_table = of_match_ptr(arizona_of_match),
},
.probe = arizona_spi_probe,
.remove = arizona_spi_remove,
.id_table = arizona_spi_ids, // Contains "wm5102" and "wm5110"
};
This is an excerpt from here.
So what is the difference between arizona_spi_driver.id_table and arizona_spi_driver.driver.of_match_table?
There are several mechanism for driver matching. The id_table is intended to be used for finding a match from stripped device-tree entries (without vendor part), while of_match_table is used to find a match from full device-tree entries (the ones with vendor part).
If you check, arizona_of_match is defined as this:
const struct of_device_id arizona_of_match[] = {
{ .compatible = "wlf,wm5102", .data = (void *)WM5102 },
{ .compatible = "wlf,wm5110", .data = (void *)WM5110 },
{ .compatible = "wlf,wm8280", .data = (void *)WM8280 },
{ .compatible = "wlf,wm8997", .data = (void *)WM8997 },
{},
};
wlf is the vendor part for this case, while arizona_spi_ids doesn't contain the vendor part.
Hence, if you have something like this in your device tree:
compatible = "myvendor,wm5102"
Your device will match against id_table but not against of_match_table since the vendor is different.
The kernel will do matching against of_match_table first before check id_table (see spi_get_device_id in here). The device matching priority is: of_match_table > acpi_driver > id_table.

What's the structure member 'pm' in the driver structure?

What's 'pm' and 'of_match_table' in the following spi driver code
static struct platform_driver omap2_mcspi_driver = {
.driver = {
.name = "omap2_mcspi",
.owner = THIS_MODULE,
.pm = &omap2_mcspi_pm_ops,
.of_match_table = omap_mcspi_of_match,
},
.probe = omap2_mcspi_probe,
.remove = omap2_mcspi_remove,
};
First, take a look on From where platform device gets it name. You can find more details on ACPI based device enumeration.

How to change LED trigger?

I have register in BSP's the LED:
static struct gpio_led ic_leds[] = {
{
.name = "led1:green",
.gpio = USER_LED,
.default_trigger = "heartbeat",
.active_low = 1,
},
};
static struct gpio_led_platform_data ic_led_info = {
.num_leds = ARRAY_SIZE(ic_leds),
.leds = ic_leds,
};
static struct platform_device ic_leds_device = {
.name = "leds-gpio",
.id = -1,
.dev = {
.platform_data = &ic_led_info,
},
};
static void __init ic_add_device_leds(void)
{
platform_device_register(&ic_leds_device);
}
How can I change the trigger in run time? I know that it's possible with sysfs, but maybe exist another way?
echo "thetriggeryouwant" > /sys/class/leds/someled/trigger
where thetriggeryouwant is for example phy0rx and someled is the name of the led you want to change the trigger for.
To get all available triggers for that led, you can cat the file:
cat /sys/class/leds/someled/trigger
gives for example:
[none] timer oneshot mtd nand-disk heartbeat backlight gpio cpu cpu0 cpu1 activity default-on 2188000.ethernet-2:00:link 2188000.ethernet-2:00:100Mbps 2188000.ethernet-2:00:10Mbps
where the item in brackets ([none]) denotes the current trigger.

Resources