This post will give a simple introduction to Linux kernel module(Part II.).
Linux kernel module简介(二)
Let’s continue the unfinished parts we left in Part I..
regmap is a new API added in kernel 3.1. It helps to provide a abstraction for I2C/SPI/IRQ etc. operations. If chips provide both I2C and SPI interfaces, using regmap also can help to reuse part of code. In this example(st_uvis25, a UVI sensor), it provides another SPI driver(st_uvis25_spi.c), and a interfaces-nonrelevant file(st_uvis25_core.c) as well. st_uvis25_core.c will not care which kind of interfaces you are using, every I2C/SPI read/write will be done through regmap. If you put your device on I2C bus in dts file, regmap will call I2C operate functions when you use regmap_write, if it’s on SPI bus, regmap will call SPI operate functions instead.
Tos use regmap API, a regmap_config should be defined. reg_bits and val_bits defined the register address length and data length inside this device. write_flag_mask and read_flag_mask will do OR operation with the data you trying to send/read(they are optional):
// linux-4.9/drivers/base/regmap/regmap.c, Line 2002
Then use devm_regmap_init_i2c or devm_regmap_init_spi to initialize your regmap. It will help you to allocate memory for your regmap and release it when module remove.
Let’s take a look at st_uvis25.h and st_uvis25_core.c:
// st_uvis25.h, Line 26
// st_uvis25_core.c Line 55
This st_uvis25_check_whoami uses regmap_read to read value from register ST_UVIS25_REG_WHOAMI_ADDR and compares it to ST_UVIS25_REG_WHOAMI_VAL.
In last post we already know that module_i2c_driver actually are encapsulations of module_init/exit, so it’s easy to understand that st_uvis25_i2c_probe will be called when install mod. But how about st_uvis25_probe, where does it come from?
As I mentioned in last section, there are two more files, this st_uvis25_probe is export from one of them(st_uvis25_core.c):
int st_uvis25_probe(struct device *dev, int irq, struct regmap *regmap)
EXPORT_SYMBOL is a marco defined in linux-4.9/include/linux/export.h
// linux-4.9/include/linux/export.h, Line 56
In newer kernel 4.19.9, this marco has been simplified to:
/* For every exported symbol, place a struct in the __ksymtab section */
When you use it as EXPORT_SYMBOL(my_export, GPL),it will be expanded like this:
extern typeof(my_export) my_export; \
It will be simpler if ignore attribute and __used(there are gcc attributes) and expand again:
static const char __kstrtab_my_export =” my_export”;
This part of code declared a static const char array to store symbol name and a static const struct to store address and name of this symbol.
If we add attribute back again, this char array will be put into section __ksymtab_strings and struct will be put into section __ksymatab_gpl.
How to call drivers in user space will be discussed in Part III.
To be continued…