Probe function in linux

Who calls the probe() of driver

How does probe() call gets called? Who calls it? As per my understanding, __init() registers driver and then somehow probe() is called to register the device data and irq etc. How exactly it happens? I am working on touchscreen driver and its __init registers itself to i2c driver . Then probe expect i2c_clien t data which returns null. I want to track where it gets filled.

6 Answers 6

Long story short: the probe() function of the driver is called as a result of calling the register_driver for that specific bus. More precisely, it’s called by the probe() of that bus_type structure. In your case: i2c_bus_type .

Here’s the call chain in your I2C case:

  • i2c_register_driver
  • driver_register
  • bus_add_driver
  • driver_attach
  • __driver_attach (for your device)
  • driver_probe_device
  • really_probe
  • i2c_device_probe (this is what dev->bus->probe is for an i2c driver)
  • your_probe_function

When does i2c_register_driver get called? Is it when you call i2cdetect and it finds a device on the bus with a name that matches a registered struct i2c_driver ?

I have prepared a graph that traces platform drive’s probe function. You are working with I2C driver which AFAIK is a platform driver. I hope this helps you to trace the issue.

enter image description here

Also, look into following link to see the discussion on kernelnewbies.

Lets consider an example of a platform device driver :

  1. The starting trigger function for the driver->probe() callback is the module_init() macro called while loading the driver; this macro is defined in include/linux/module.h .
  2. module_init(my_driver_init) has the callback to my_driver_init() function. my_driver_init() function should have a call to platform_driver_register(my_driver)
  3. platform_driver_register(my_driver) assigns my_driver -> probe() handle to generic drv -> probe() and calls the driver_register(my_driver) function.
  4. driver_register(my_driver) function adds my_driver to the platform bus and calls driver_attach() function.
  5. In the same way, even the platform_device needs to attach to the platform bus.
  6. Finally, only if the driver_match_device() returns success based on the .name & .id_table of the driver matches in the platform devices list that comes either from ACPI/DTS , then the driver_probe_device() gets called that has the drv->probe() callback.
Читайте также:  Debian подключить сетевой диск linux

@iSegFault : probe() will be called to make sure that the device exist and the functionality is fine.If device is not hot-pluggable, functionality of probe() can be put inside init() method.This will reduce driver’s run time memory footprint. P.S link

Probe() happens at the time of device boot or when device is connected.For a «platform» device the probe function is invoked when a platform device is registered and it’s device name matches the name specified on the device driver. P.S link

The i2c_detect function probes the I2C adapter, looking for the different addresses specified in the addr_data structure. If a device is found, the chip_detect function then is called. P.S link.

One link that will surely clear your doubt. P.S link

In kernel 2.4.29, i can show you that how does probe happen ? Please see below (File name: drivers/acorn/char/pcf8583.c)

static struct i2c_driver pcf8583_driver = < name: "PCF8583", id: I2C_DRIVERID_PCF8583, flags: I2C_DF_NOTIFY, attach_adapter: pcf8583_probe, /* This will be called from i2c-core.c P.S see below function i2c_add_driver()*/ detach_client: pcf8583_detach, command: pcf8583_command >; 

File Name: drivers/i2c/i2c-core.c

int i2c_add_driver(struct i2c_driver *driver) < . . /* now look for instances of driver on our adapters */ if (driver->flags& (I2C_DF_NOTIFY|I2C_DF_DUMMY)) < for (i=0;iattach_adapter(adapters[i]); /*This is a location from where probe is called. Pointer **driver** is of type **pcf8583_driver** which you have passed into this function*/ > ADAP_UNLOCK(); return 0; > 

In PCI for kernel-2.4.29, it gets called when vendor and device id are identified. PCI bus driver do this for you. Please see below code:

File Name: drivers/pci/pci.c

static int pci_announce_device(struct pci_driver *drv, struct pci_dev *dev) < const struct pci_device_id *id; int ret = 0; if (drv->id_table) < dev); /* check for device presence*/ if (!id) < ret = 0; goto out; >> else dev_probe_lock(); if (drv->probe(dev, id) >= 0) < /* This is a location from where probe is called*/ dev->driver = drv; ret = 1; > dev_probe_unlock(); out: return ret; > 

Источник

Using the Linux Kernel Tracepoints¶

This document introduces Linux Kernel Tracepoints and their use. It provides examples of how to insert tracepoints in the kernel and connect probe functions to them and provides some examples of probe functions.

Purpose of tracepoints¶

A tracepoint placed in code provides a hook to call a function (probe) that you can provide at runtime. A tracepoint can be «on» (a probe is connected to it) or «off» (no probe is attached). When a tracepoint is «off» it has no effect, except for adding a tiny time penalty (checking a condition for a branch) and space penalty (adding a few bytes for the function call at the end of the instrumented function and adds a data structure in a separate section). When a tracepoint is «on», the function you provide is called each time the tracepoint is executed, in the execution context of the caller. When the function provided ends its execution, it returns to the caller (continuing from the tracepoint site).

You can put tracepoints at important locations in the code. They are lightweight hooks that can pass an arbitrary number of parameters, which prototypes are described in a tracepoint declaration placed in a header file.

They can be used for tracing and performance accounting.

Usage¶

Two elements are required for tracepoints :

In order to use tracepoints, you should include linux/tracepoint.h.

#undef TRACE_SYSTEM #define TRACE_SYSTEM subsys #if !defined(_TRACE_SUBSYS_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_SUBSYS_H #include DECLARE_TRACE(subsys_eventname, TP_PROTO(int firstarg, struct task_struct *p), TP_ARGS(firstarg, p)); #endif /* _TRACE_SUBSYS_H */ /* This part must be outside protection */ #include 

In subsys/file.c (where the tracing statement must be added):

#include #define CREATE_TRACE_POINTS DEFINE_TRACE(subsys_eventname); void somefct(void)

  • subsys_eventname is an identifier unique to your event
    • subsys is the name of your subsystem.
    • eventname is the name of the event to trace.

    Connecting a function (probe) to a tracepoint is done by providing a probe (function to call) for the specific tracepoint through register_trace_subsys_eventname(). Removing a probe is done through unregister_trace_subsys_eventname(); it will remove the probe.

    tracepoint_synchronize_unregister() must be called before the end of the module exit function to make sure there is no caller left using the probe. This, and the fact that preemption is disabled around the probe call, make sure that probe removal and module unload are safe.

    The tracepoint mechanism supports inserting multiple instances of the same tracepoint, but a single definition must be made of a given tracepoint name over all the kernel to make sure no type conflict will occur. Name mangling of the tracepoints is done using the prototypes to make sure typing is correct. Verification of probe type correctness is done at the registration site by the compiler. Tracepoints can be put in inline functions, inlined static functions, and unrolled loops as well as regular functions.

    The naming scheme «subsys_event» is suggested here as a convention intended to limit collisions. Tracepoint names are global to the kernel: they are considered as being the same whether they are in the core kernel image or in modules.

    If the tracepoint has to be used in kernel modules, an EXPORT_TRACEPOINT_SYMBOL_GPL() or EXPORT_TRACEPOINT_SYMBOL() can be used to export the defined tracepoints.

    If you need to do a bit of work for a tracepoint parameter, and that work is only used for the tracepoint, that work can be encapsulated within an if statement with the following:

    All trace_() calls have a matching trace__enabled() function defined that returns true if the tracepoint is enabled and false otherwise. The trace_() should always be within the block of the if (trace__enabled()) to prevent races between the tracepoint being enabled and the check being seen.

    The advantage of using the trace__enabled() is that it uses the static_key of the tracepoint to allow the if statement to be implemented with jump labels and avoid conditional branches.

    The convenience macro TRACE_EVENT provides an alternative way to define tracepoints. Check http://lwn.net/Articles/379903, http://lwn.net/Articles/381064 and http://lwn.net/Articles/383362 for a series of articles with more details.

    If you require calling a tracepoint from a header file, it is not recommended to call one directly or to use the trace__enabled() function call, as tracepoints in header files can have side effects if a header is included from a file that has CREATE_TRACE_POINTS set, as well as the trace_() is not that small of an inline and can bloat the kernel if used by other inlined functions. Instead, include tracepoint-defs.h and use tracepoint_enabled().

    void do_trace_foo_bar_wrapper(args)
    DECLARE_TRACEPOINT(foo_bar); static inline void some_inline_function()

    Источник

Оцените статью
Adblock
detector