我正在尝试为BeagleBone Black编写一个内核模块,该模块将与我的自定义I2C从设备通信。我尝试了以下几个内核模块开发教程,它们在某些时候似乎都不完整,或者假设我知道我显然不知道的那些事情。...我现在的当前问题是Makefile没有看到i2c_register_board_info
符号。我将此驱动程序编写为一个单独的模块,在内核编译期间未对其进行编译。另外,在使用buildroot进行构建时,我已经启用了I2C工具。使用I2C工具,我可以检测到设备并与之交互。我的Makefile如下所示:
MODULE_NAME = PowerManagerDriver
PWD := $(shell pwd)
SRC_DIR = user_files
BUILD_DIR = build
BUILD_EXT = *.o .*.cmd *.ko *.mod.c *.order *.symvers *.dwo
SRCS = $(SRC_DIR)/main.c $(SRC_DIR)/pmd_i2c.c
OBJS = $(SRCS:.c=.o)
obj-m += $(MODULE_NAME).o
$(MODULE_NAME)-y = $(OBJS)
KERNELDIR ?= /home/lukasz/brl/Machine/beaglebone/build/linux-a75d8e93056181d512f6c818e8627bd4554aaf92
all: default
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
mv $(SRC_DIR)/*.o $(BUILD_DIR)/
mv $(BUILD_EXT) $(BUILD_DIR)/ &> /dev/null
clean:
rm -rf $(BUILD_DIR)/*
rm -rf $(BUILD_EXT)
make
输出:
13:45:33 **** Incremental Build of configuration Default for project PowerManagerDriver ****
make ARCH=arm CROSS_COMPILE=arm-buildroot-linux-uclibcgnueabihf- -j6 all
make -C /home/lukasz/brl/Machine/beaglebone/build/linux-a75d8e93056181d512f6c818e8627bd4554aaf92 M=/home/lukasz/eclipse-workspace/PowerManagerDriver modules
make[1]: Entering directory '/home/lukasz/brl/Machine/beaglebone/build/linux-a75d8e93056181d512f6c818e8627bd4554aaf92'
CC [M] /home/lukasz/eclipse-workspace/PowerManagerDriver/user_files/main.o
CC [M] /home/lukasz/eclipse-workspace/PowerManagerDriver/user_files/pmd_i2c.o
/home/lukasz/eclipse-workspace/PowerManagerDriver/user_files/pmd_i2c.c:99:26: warning: ‘pdm_i2cClient’ defined but not used [-Wunused-variable]
static struct i2c_client pdm_i2cClient = { 0 };
^
LD [M] /home/lukasz/eclipse-workspace/PowerManagerDriver/PowerManagerDriver.o
Building modules, stage 2.
MODPOST 1 modules
WARNING: "i2c_register_board_info" [/home/lukasz/eclipse-workspace/PowerManagerDriver/PowerManagerDriver.ko] undefined!
CC /home/lukasz/eclipse-workspace/PowerManagerDriver/PowerManagerDriver.mod.o
LD [M] /home/lukasz/eclipse-workspace/PowerManagerDriver/PowerManagerDriver.ko
make[1]: Leaving directory '/home/lukasz/brl/Machine/beaglebone/build/linux-a75d8e93056181d512f6c818e8627bd4554aaf92'
mv user_files/*.o build/
mv *.o .*.cmd *.ko *.mod.c *.order *.symvers *.dwo build/ &> /dev/null
13:45:35 Build Finished. 0 errors, 1 warnings. (took 1s.394ms)
到目前为止,我只有很少的I2C接口功能:
static int pdm_i2cProbe(struct i2c_client* client,
const struct i2c_device_id* id)
{
PMD_ASSERT(client);
PMD_ASSERT(id);
return 0;
}
static struct i2c_driver pdm_i2cDriver =
{
.driver =
{
.name = "pdm-driver",
.owner = THIS_MODULE,
},
.probe = pdm_i2cProbe,
};
static struct i2c_board_info pdm_i2cBoardInfo[] =
{
{
I2C_BOARD_INFO("pdm-driver", 0x30),
.irq = 69,
},
};
/**
* @brief Initializes the I2C module.
* @param busNr: The I2C peripheral number on which the device is connected.
* @return \ref e_pdmStatus_OK on succesfull init.
*/
pmdStatus_t pdm_i2cInit(const unsigned int busNr)
{
if (i2c_register_board_info((int)busNr, pdm_i2cBoardInfo,
ARRAY_SIZE(pdm_i2cBoardInfo)))
return e_pmdStatus_BADPARAM;
if (i2c_add_driver(&pdm_i2cDriver))
return e_pmdStatus_EXE;
return e_pmdStatus_OK;
}
在这一点上,尽管我没有探测任何东西,但是由于探测功能为空,所以我希望至少能够正确加载模块。由于找不到i2c_register_board_info
,因此我什至没有进入测试阶段。构建内核时的.config文件由以下几行组成:
# I2C support
#
CONFIG_I2C=y
CONFIG_I2C_BOARDINFO=y
CONFIG_I2C_COMPAT=y
CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_MUX is not set
CONFIG_I2C_HELPER_AUTO=y
我以前i2c registering macro not found?找到了这个话题,但是我什么都没得到。
尝试按要求使用insmod加载模块时:
# uname -a
Linux buildroot 4.9.59 #1 SMP Fri Oct 5 11:55:54 CEST 2018 armv7l GNU/Linux
# insmod PowerManagerDriver.ko
[ 39.438108] PowerManagerDriver: loading out-of-tree module taints kernel.
[ 39.445800] PowerManagerDriver: Unknown symbol i2c_register_board_info (err 0)
[ 39.455743] PowerManagerDriver: Unknown symbol i2c_register_board_info (err 0)
insmod: can't insert 'PowerManagerDriver.ko': unknown symbol in module, or unknown parameter
#
答案 0 :(得分:1)
如果“保证”您的硬件存在,则无需强制性定义设备。您可以使用设备树(dtb)在特定总线上的特定地址处声明从属设备的存在,为驱动程序提供参数等。因此,您的模块无需执行寄存器板信息之类的事情。
在文档中对此进行了解释:https://www.kernel.org/doc/Documentation/i2c/instantiating-devices
换句话说,您应该能够仅使用开放式固件(of
)钩子和填充的设备树(dtb)将作为从属设备的驱动程序编写为内核模块。
答案 1 :(得分:0)
好的,听起来好像是Build Linux Kernel module with warning i2c_register_board_info undefined的副本。
问题:
# insmod PowerManagerDriver.ko
[ 39.438108] PowerManagerDriver: loading out-of-tree module taints kernel.
[ 39.445800] PowerManagerDriver: Unknown symbol i2c_register_board_info (err 0)
[ 39.455743] PowerManagerDriver: Unknown symbol i2c_register_board_info (err 0)
insmod: can't insert 'PowerManagerDriver.ko': unknown symbol in module, or unknown parameter
原因:
Build Linux Kernel module with warning i2c_register_board_info undefined
未导出功能i2c_register_board_info(使用EXPORT_SYMBOL) 用于内核模块。只有编译到内核中的代码才能使用 功能。据我的描述了解,该功能 供董事会开发人员使用
您的问题是您在一个驱动程序中混合了两种东西,即驱动程序 本身可以是模块和平台(旧版!)代码,而不能。 您必须删除ACPI或设备树资源的平台代码 提供程序,或者作为最后的手段将其拆分到另一个编译单元。
担心:
我删除了i2c_register_board_info,然后可以为模块构建驱动程序 (.ko),而不会发出警告,并且可以通过在init中添加这些功能进行insmod 由module_init调用的函数:
... adapter = i2c_get_adapter(CONFIG_I2C_BUS); ... client = i2c_new_device(adapter, &i2c_pn535_sample_devs); ...
不确定是好是坏。因为当我删除驱动程序(rmmod)时, 驱动程序无法释放设备,并且无法再次进行insmod,我必须 再次将设备重启到insmod
如果您找到其他解决方案,或者更好的解决方案,请随时添加(并接受!)您自己的答复。
对不起,我帮不上忙:(