i2c_寄存器_板_信息符号未定义

i2c_寄存器_板_信息符号未定义,c,linux-kernel,kernel-module,i2c,C,Linux Kernel,Kernel Module,I2c,我正在尝试为BeagleBone Black编写一个内核模块,该模块将与我定制的I2C从设备进行通信。我尝试了以下几个内核模块开发教程,它们在某一点上似乎都不完整,或者假设我知道一些我显然不知道的东西。。。我现在的问题是Makefile没有看到i2c\u寄存器\u板\u信息符号。我将这个驱动程序作为一个单独的模块编写,它不是在内核编译期间编译的。另外,我在使用buildroot构建时启用了I2C工具。使用I2C工具,我能够检测设备并与之连接。我的Makefile如下所示: MODULE_NAME

我正在尝试为BeagleBone Black编写一个内核模块,该模块将与我定制的I2C从设备进行通信。我尝试了以下几个内核模块开发教程,它们在某一点上似乎都不完整,或者假设我知道一些我显然不知道的东西。。。我现在的问题是Makefile没有看到
i2c\u寄存器\u板\u信息
符号。我将这个驱动程序作为一个单独的模块编写,它不是在内核编译期间编译的。另外,我在使用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)
生成
输出:

到目前为止,我只有几个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\u寄存器\u板\u信息。构建内核时的My.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
我以前发现过这个话题,但我从中什么也得不到

当尝试按要求使用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
#

好的,听起来像是一个复制品

问题:

# 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
原因:

功能i2c_寄存器_板_信息未导出(带导出符号) 对于内核模块。只有编译到内核中的代码才可以使用这种方法 功能。据我所知,从它的描述,功能 供开发人员使用

您的问题是,您在一个驱动程序中混合了两种东西,即驱动程序 它本身可以是一个模块和平台(遗留!)代码,但不能。 您必须删除ACPI或设备树资源的平台代码 提供程序,或者作为将其拆分到另一个编译单元的最后手段

解决方法:

我删除了i2c_寄存器_板_信息,然后我可以构建模块驱动程序 (.ko)没有警告,可以通过在init中添加这些函数来insmod 模块_init调用的函数:

... 
adapter = i2c_get_adapter(CONFIG_I2C_BUS); 
... 
client = i2c_new_device(adapter, &i2c_pn535_sample_devs); 
... 
不确定是好是坏。因为当我移除驱动程序(rmmod)时, 驱动程序不释放设备,无法再次insmod,我必须 重新启动设备到insmod

如果您找到了不同的或更好的解决方案,请随时添加(并接受!)您自己的回答


很抱歉,我无法提供更多帮助:(

如果您的硬件“保证”在那里,您不需要强制定义设备。您可以使用设备树(dtb)要在特定总线上的特定地址声明从属设备的存在,请向驱动程序提供参数等。这样,您的模块就不需要做注册板信息的事情

这些文件对此进行了解释:


换句话说,您应该能够只使用开放固件(
)挂钩和填充的设备树(dtb)为从设备编写作为内核模块的驱动程序-但你自己已经找到了…它没有给出任何结论性的答案。看,它是德语的…但它可能会给你你想要的答案。而且:因为它是一个“警告”…您可能可以加载并运行您的.ko anway。请发回您所学的内容!您好,我会检查一下,谢谢您。我尝试加载模块,但收到了关于丢失符号的相同消息。问:成功了吗?另外:看:git clonegit://github.com/derekmolloy/beaglebone.  它可能会提供一些关于配置工具链的有用提示…只是一个想法…@paulsm4嗨,还没有。如果我正确理解了所有内容,那么在将驱动程序编译为外部模块时,我似乎看不到这个符号…我需要在内核编译过程中使用buildroot编译它。不幸的是,我还没有想出怎么做。至于Derek Molloys的教程,我遵循了INF到目前为止,非常有用。可能是重复的。谢谢你的回答。你能详细说明一下你提到的
api的
是什么吗?@Bremen我指的是Linux内核钩子,用于向OpenFirmware(of)注册你的驱动程序子系统。查看此部分并找到
部分的
#ifdef CONFIG_。这是让内核知道如何应用devicetree(DTB)指令来加载和配置驱动程序的部分。您需要修改此部分以适应您的硬件使用情况。
... 
adapter = i2c_get_adapter(CONFIG_I2C_BUS); 
... 
client = i2c_new_device(adapter, &i2c_pn535_sample_devs); 
...