Which suspend/resume pointer is the right one to use? - linux-kernel

I am working on power management on an i2c driver and noticed something odd.
include/linux/i2c.h
struct i2c_driver {
//...
int (*suspend)(struct i2c_client *, pm_message_t mesg);
int (*resume)(struct i2c_client *);
//...
struct device_driver driver;
//...
}
include/linux/device.h
struct device_driver {
//...
int (*suspend) (struct device *dev, pm_message_t state);
int (*resume) (struct device *dev);
//...
const struct dev_pm_ops *pm;
//...
}
include/linux/pm.h
struct dev_pm_ops {
//...
int (*suspend)(struct device *dev);
int (*resume)(struct device *dev);
//...
}
Why are there so many suspend and resume function pointers? Some kind of legacy thing? Which one should I use for my driver?
I am on an old kernel (2.6.35)
Thanks!

Why are there so many suspend and resume function pointers?
i2c_driver - legacy support.
device_driver - standard support.
dev_pm_ops - extended power management.
Notice that they are all function pointers. There is sequencing for the suspend and resume. For instance, the i2c controller must be suspended after the devices but resumed before.
Some kind of legacy thing?
The struct i2c_driver is a legacy mechism. It existed before the entire power infrastructure was created. As well, some configurations may exclude the full struct dev_pm_ops pointer, but have the suspend and resume driver hooks. The full struct dev_pm_ops supports suspend to disk and other features. Suspend to memory is more common and is given pointers space in struct device_driver. If struct dev_pm_ops is non-NULL, the two pointer will be the same. These two should call the same routine in your driver.
Which one should I use for my driver?
You probably shouldn't use any of them. It is probably more likely that your driver is part of some other sub-system. see Note For instance, the i2c is used in codecs like the wm8940.c. Generally, i2c is not the central controlling sub-system. It is a driver that is used by something else to control a chip-set. The sound sub-system will be suspended before i2c and it is better to put your hooks there. If your driver is pure i2c, then use the macros in pm.h, like SET_SYSTEM_SLEEP_PM_OPS to conditionalize the setting of dev_pm_ops; so set both of them. Most likely the device_driver will be copied to dev_pm_ops if it exists, but doing it explicitly is better.
The driver-model, i2c power management and power driver documentation have more information on the structure and overviews.
Note: In this case, there are multiple device_driver structures. Usually the i2c_driver is managed by a controlling driver. The controlling driver should implement a suspend/resume for it's sub-system, which uses the i2c_driver interface.

Related

How to use kernel GPIO descriptor interface

I'm trying to develop a simple Linux kernel module that manages a bunch of sensors/actuators pinned on the GPIO of a Raspberry Pi.
The GPIO functionalities I need are quite simple: get/set pin values, receive IRQs, ...
In my code, I have a misc_device which implements the usual open, read, write and open operations. In my read operation, for instance, I'd like to get the value (high/low) of a specific GPIO pin.
Luckily, the kernel provides an interface for such GPIO operations. Actually, there are two interfaces, according to the official GPIO doc: the legacy one, which is extremely simple yet deprecated, and the new descriptor-based one.
I'd like to use the latter for my project, and I understand how to implement all I need except for one thing: the device tree stuff.
With reference to board.txt, before I can call gpiod_get_index() and later gpiod_get_value(), first I need to setup the device tree somehow like this:
foo_device {
compatible = "acme,foo";
...
led-gpios = <&gpio 15 GPIO_ACTIVE_HIGH>, /* red */
<&gpio 16 GPIO_ACTIVE_HIGH>, /* green */
<&gpio 17 GPIO_ACTIVE_HIGH>; /* blue */
power-gpios = <&gpio 1 GPIO_ACTIVE_LOW>;
};
However, I've absolutely no clue where to put that chunk of code, nor if I really need it. Mind that I have a misc device which looks like this, where aaa_fops contains the read operation:
static struct miscdevice aaa = {
MISC_DYNAMIC_MINOR, "aaa", &aaa_fops
};
Using the old deprecated interface, my problem would be solved because it doesn't require to mess with the device tree, but I'd still like to use the new one if not too complex.
I've read a bunch of documentation, both official and unofficial, but couldn't find a straight and simple answer to my issue. I tried to find an answer in the kernel source code, especially in the drivers section, but only got lost in a valley of complex and messy stuff.
The lack of working, minimal examples (WME) about kernel is significantly slowing down my learning process, just my opinion about it.
Could you please give me a WME of a simple device (preferably a misc) whose read() operation gets the value of a pin, using the new GPIO interface?
If you need more details about my code, just ask. Thanks in advance!
Note 1: I'm aware that most of my work could be done in userspace rather than kernelspace; my project is for educational purposes only, to learn the kernel.
Note 2: I choose a misc device because it's simple, but I can switch to a char device if needed.
... first I need to setup the device tree somehow like this:
...
However, I've absolutely no clue where to put that chunk of code
Device Tree nodes and properties should not be called "code".
Most devices are connected to a peripheral bus, so device nodes typically are child nodes of the peripheral bus node.
Could you please give me a WME of a simple device
You can find numerous examples of descriptor-based GPIO usage in the kernel source.
Since the documentation specifies the GPIO descriptor as a property named
<function>-gpios, a grep of the directory arch/arm/boot/dts for the string "\-gpios" reports many possible examples.
In particular there's
./bcm2835-rpi-b.dts: hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>;
This hpd-gpios property belongs to the hdmi base-node defined in bcm283x.dtsi, and is used by the gpu/drm/vc4/vc4_hdmi.c driver.
/* General HDMI hardware state. */
struct vc4_hdmi {
...
int hpd_gpio;
...
};
static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
{
...
/* Only use the GPIO HPD pin if present in the DT, otherwise
* we'll use the HDMI core's register.
*/
if (of_find_property(dev->of_node, "hpd-gpios", &value)) {
...
hdmi->hpd_gpio = of_get_named_gpio_flags(dev->of_node,
"hpd-gpios", 0,
&hpd_gpio_flags);
if (hdmi->hpd_gpio < 0) {
ret = hdmi->hpd_gpio;
goto err_unprepare_hsm;
}
...
}
If the hpd-gpios property is defined/found and successfully retrieved from the board's DeviceTree, then the driver's structure member hpd_gpio holds the GPIO pin number.
Since this driver does not call devm_gpio_request(), the framework apparently allocates the GPIO pin for the driver.
The driver can then access the GPIO pin.
static enum drm_connector_status
vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
{
...
if (vc4->hdmi->hpd_gpio) {
if (gpio_get_value_cansleep(vc4->hdmi->hpd_gpio) ^
vc4->hdmi->hpd_active_low)
return connector_status_connected;
else
return connector_status_disconnected;
}

How to call MmGetPhysicalMemoryRanges in driver to get memory range?

I am writing a driver in which i want the exact range of RAM. I came to know about memory manager routines inside windows kernel. I am planning to include MmGetPhysicalMemoryRanges routine in my driver also to get memory range.
I don't know how to add these routines into driver..
Anyone please tell me how to write this routine??What is its syntax???
NTKERNELAPI
PPHYSICAL_MEMORY_RANGE
MmGetPhysicalMemoryRanges (
VOID
);
Where PHYSICAL_MEMORY_RANGE is:
typedef struct _PHYSICAL_MEMORY_RANGE {
PHYSICAL_ADDRESS BaseAddress;
LARGE_INTEGER NumberOfBytes;
} PHYSICAL_MEMORY_RANGE, *PPHYSICAL_MEMORY_RANGE;

add attribute to an existing kobject

I'm working on porting a driver I've written for the 2.6.x kernel series into 3.x (i.e. RH EL 6 -> RH EL 7). My driver solution actually comes in two modules: a modified form of ahci.c (from the kernel tree) and my own upper-layer character driver for access AHCI registers and even executing commands against the drive.
In porting to CentOS 7, I've run into an interesting problem. Changes to the drivers I'm building on remove the access to the scsi_host attributes in SYSFS. My question then is, can I append attributes onto devices already existing in SYSFS? Every example I've come across shows making the attributes at the point of device creation, e.g.:
static ssize_t port_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buff);
static struct kobj_attribute pxclb_attr = __ATTR(pxclb, 0664, port_show, NULL);
static struct attribute *attrs[] = {
&pxclb_attr.attr,
NULL,
};
static struct attribute_group port_group = {
.attrs = attrs,
};
/* much other code */
sysfs_create_group(&kobj, &port_group);
This example comes from my character driver. All the searches I've done with Google, and referencing my Linux Foundation Drivers class book, all show attribute creation done at the time of device creation. Can I add to them at any time? It would seem that one could call sysfs_create_group() at any time. Is this true?
You can add attribute in sysfs at anytime you like.
The reason that almost all the drivers add attribute in probe is that userspace has strict expectations on when attributes get created. When a new device is registered in the kernel, a uevent is generated to notify userspace (like udev) that a new device is available. If attributes are added after the device is registered, then userspace won't get notified and userspace will not know about the new attributes.

Can I query device tree items without creating a platform device?

I am writing a kernel module intended to functionally test a device driver kernel module for an ARM+FPGA SOC system. My approach involves finding which interrupts the device driver is using by querying the device tree. In the device driver itself, I register a platform driver using platform_driver_register and in the .probe function I am passed a platform_device* pointer that contains the device pointer. With this I can call of_match_device and irq_of_parse_and_map, retrieving the irq numbers.
I don't want to register a second platform driver just to query the device tree this way in the test module. Is there some other way I can query the device tree (perhaps more directly, by name perhaps?)
This is what I've found so far, and it seems to work. of_find_compatible_node does what I want. Once I have the device_node*, I can call irq_of_parse_and_map (since of_irq_get_byname doesn't seem to compile for me). I can use it something like the following:
#include <linux/of.h>
#include <linux/of_irq.h>
....
int get_dut_irq(char* dev_compatible_name)
{
struct device_node* dev_node;
int irq = -1;
dev_node = of_find_compatible_node(NULL, NULL, dev_compatible_name);
if (!dev_node)
return -1;
irq = irq_of_parse_and_map(dev_node, 0);
of_node_put(dev_node);
return irq;
}

Linux Device Driver Program, where the program starts?

I've started to learn Linux driver programs, but I'm finding it a little difficult.
I've been studying the i2c driver, and I got quite confused regarding the entry-point of the driver program. Does the driver program start at the MOUDULE_INIT() macro?
And I'd also like to know how I can know the process of how the driver program runs. I got the book, Linux Device Driver, but I'm still quite confused. Could you help me? Thanks a lot.
I'll take the i2c driver as an example. There are just so many functions in it, I just wanna know how I can get coordinating relation of the functions in the i2c drivers?
A device driver is not a "program" that has a main {} with a start point and exit point. It's more like an API or a library or a collection of routines. In this case, it's a set of entry points declared by MODULE_INIT(), MODULE_EXIT(), perhaps EXPORT_SYMBOL() and structures that list entry points for operations.
For block devices, the driver is expected to provide the list of operations it can perform by declaring its functions for those operations in (from include/linux/blkdev.h):
struct block_device_operations {
int (*open) ();
int (*release) ();
int (*ioctl) ();
int (*compat_ioctl) ();
int (*direct_access) ();
unsigned int (*check_events) ();
/* ->media_changed() is DEPRECATED, use ->check_events() instead */
int (*media_changed) ();
void (*unlock_native_capacity) ();
int (*revalidate_disk) ();
int (*getgeo)();
/* this callback is with swap_lock and sometimes page table lock held */
void (*swap_slot_free_notify) ();
struct module *owner;
};
For char devices, the driver is expected to provide the list of operations it can perform by declaring its functions for those operations in (from include/linux/fs.h):
struct file_operations {
struct module *owner;
loff_t (*llseek) ();
ssize_t (*read) ();
ssize_t (*write) ();
ssize_t (*aio_read) ();
ssize_t (*aio_write) ();
int (*readdir) ();
unsigned int (*poll) ();
long (*unlocked_ioctl) ();
long (*compat_ioctl) ();
int (*mmap) ();
int (*open) ();
int (*flush) ();
int (*release) ();
int (*fsync) ();
int (*aio_fsync) ();
int (*fasync) ();
int (*lock) ();
ssize_t (*sendpage) ();
unsigned long (*get_unmapped_area)();
int (*check_flags)();
int (*flock) ();
ssize_t (*splice_write)();
ssize_t (*splice_read)();
int (*setlease)();
long (*fallocate)();
};
For platform devices, the driver is expected to provide the list of operations it can perform by declaring its functions for those operations in (from include/linux/platform_device.h):
struct platform_driver {
int (*probe)();
int (*remove)();
void (*shutdown)();
int (*suspend)();
int (*resume)();
struct device_driver driver;
const struct platform_device_id *id_table;
};
The driver, especially char drivers, does not have to support every operation listed. Note that there are macros to facilitate the coding of these structures by naming the structure entries.
Does the driver program starts at the MOUDLUE_INIT() macro?
The driver's init() routine specified in MODULE_INIT() will be called during boot (when statically linked in) or when the module is dynamically loaded. The driver passes its structure of operations to the device's subsystem when it registers itself during its init().
These device driver entry points, e.g. open() or read(), are typically executed when the user app invokes a C library call (in user space) and after a switch to kernel space. Note that the i2c driver you're looking at is a platform driver for a bus that is used by leaf devices, and its functions exposed by EXPORT_SYMBOL() would be called by other drivers.
Only the driver's init() routine specified in MODULE_INIT() is guaranteed to be called. The driver's exit() routine specified in MODULE_EXIT() would only be executed if/when the module is dynamically unloaded. The driver's op routines will be called asynchronously (just like its interrupt service routine) in unknown order. Hopefully user programs will invoke an open() before issuing a read() or an ioctl() operation, and invoke other operations in a sensible fashion. A well-written and robust driver should accommodate any order or sequence of operations, and produce sane results to ensure system integrity.
It would probably help to stop thinking of a device driver as a program. They're completely different. A program has a specific starting point, does some stuff, and has one or more fairly well defined (well, they should, anyway) exit point. Drivers have some stuff to do when the first get loaded (e.g. MODULE_INIT() and other stuff), and may or may not ever do anything ever again (you can forcibly load a driver for hardware your system doesn't actually have), and may have some stuff that needs to be done if the driver is ever unloaded. Aside from that, a driver generally provides some specific entry points (system calls, ioctls, etc.) that user-land applications can access to request the driver to do something.
Horrible analogy, but think of a program kind of like a car - you get in, start it up, drive somewhere, and get out. A driver is more like a vending machine - you plug it in and make sure it's stocked, but then people just come along occasionaly and push buttons to make it do something.
Actually you are taking about (I2C) platform (Native)driver first you need to understand how MOUDULE_INIT() of platform driver got called versus other loadable modules.
/*
* module_init() - driver initialization entry point
* #x: function to be run at kernel boot time or module insertion
* module_init() will either be called during do_initcalls() (if
* builtin) or at module insertion time (if a module). There can only
* be one per module.*/
and for i2c driver you can refer this link http://www.linuxjournal.com/article/7136 and
http://www.embedded-bits.co.uk/2009/i2c-in-the-2632-linux-kernel/
Begin of a kernel module is starting from initialization function, which mainly addressed with macro __init just infront of the function name.
The __init macro indicate to linux kernel that the following function is an initialization function and the resource that will use for this initialization function will be free once the code of initialization function is executed.
There are other marcos, used for detect initialization and release function, named module_init() and module_exit() [as described above].
These two macro are used, if the device driver is targeted to operate as loadable and removeable kernel module at run time [i.e. using insmod or rmmod command]
IN short and crisp way : It starts from .probe and go all the way to init as soon you do insmod .This also registers the driver with the driver subsystem and also initiates the init.
Everytime the driver functionalities are called from the user application , functions are invoked using the call back.
"Linux Device Driver" is a good book but it's old!
Basic example:
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Name and e-mail");
MODULE_DESCRIPTION("my_first_driver");
static int __init insert_mod(void)
{
printk(KERN_INFO "Module constructor");
return 0;
}
static void __exit remove_mod(void)
{
printk(KERN_INFO "Module destructor");
}
module_init(insert_mod);
module_exit(remove_mod);
An up-to-date tutorial, really well written, is "Linux Device Drivers Series"

Resources