调试Linux中的简单char驱动程序在device_create()上失败

时间:2014-09-01 14:37:32

标签: c linux linux-kernel kernel linux-device-driver

我写了一个简单的char驱动程序,现在想要使用类在udev中自动注册它。我的代码包含加载驱动程序时调用的init函数和驱动程序加载其设备时调用的probe函数(当然还有它们的计数器等效exit和{{1} })。问题:添加新设备后,remove函数在执行probe命令时失败。 现在我想知道为什么:

我怎样才能获得有关此命令失败原因的更多信息(除此之外失败)?任何缺失的论点(比如我device_create的全局声明是否存在问题,我应该将其移至fooClass函数,这在我眼中并没有显示出来,但在许多示例中都有显示)?或任何其他监督错误?

根据我的代码,我删除了大多数返回验证(如probe)并清理函数以提高可读性。这两个变量是全局定义的:

IS_ERR()

static int foo_majNbr; static struct class *fooClass; 功能:

init

static int __init foo_init(void) { int rv; dev_t devNbr; /* Registering driver */ rv = pci_register_driver(&foo_driver); /* ----> see answer below for correct order <---- */ /* Create device class */ fooClass = class_create(THIS_MODULE, CLASS_NAME); /* Allocate device number, just one device for the moment */ rv = alloc_chrdev_region(&devNbr, 0, 1, DEVICE_NAME); foo_majNbr = MAJOR(devNbr); ... } 函数:

probe

2 个答案:

答案 0 :(得分:5)

您应至少打印错误编号以了解原因。

pr_err("%s:%d error code %d\n", __func__, __LINE__, PTR_ERR(foo_dev->dev));
  • PTR_ERR():将无效指针转换为错误代码
  • ERR_PTR():将错误代码转换为无效指针
  • IS_ERR():检查指针是否无效并包含错误代码
  • IS_ERR_OR_NULL():如上所述,加上它检查指针是否为NULL

在文件Linux/include/uapi/asm-generic/errno-base.h中,您可以找到最常见的错误。如果此错误代码对您没有帮助,您可以转到source code of device_create(),找出产生错误的位置,并了解原因。

也许在打电话之前打印device_create()的参数。

我知道,这不是那种神奇地解决你问题的答案:)但这是一种继续并找出原因的方法。

答案 1 :(得分:2)

该问题要求提供有关调试的信息,这在前一个答案中有详细说明。为了完整起见,我想分享解决device_create()失败原因背后的实际问题的方法:

查看dmesg日志后,加载模块后会显示以下呼叫历史记录:

[ 2646.982482] [foo_init:246] CALL | Function called.
[ 2646.982499] [foo_probe:121] CALL | Function called.
[ 2646.982503] [foo_probe:147] ERR -19 | Failed to add device to class.
[ 2646.982535] [foo_init:279] OK | Driver loaded, Major number: 235.

可以看出,init()函数在调用probe()之前没有完成其例行程序。因此,当probe()想要将其添加到设备时,不存在任何类。 init()中调用的命令的顺序是问题:驱动程序在完成其例程之前已经将自己注册到内核。只有在最后才能调用pci_register_driver()。这里更新了代码:

static int __init foo_init(void)
{
    int rv;
    dev_t devNbr;

    /* Create device class */
    fooClass = class_create(THIS_MODULE, CLASS_NAME);

    /* Allocate device number, just one device for the moment */
    rv = alloc_chrdev_region(&devNbr, 0, 1, DEVICE_NAME);
    foo_majNbr = MAJOR(devNbr);

    ...

    /* Registering driver */
    rv = pci_register_driver(&foo_driver);
        /* ----> has to be called at the very end! <---- */
}

正确的顺序也计入exit()函数(正如我在遇到导致Oops的另一个错误后发现的那样):首先取消注册驱动程序以取消注册设备,然后销毁该类。代码如下:

static void __exit foo_exit(void)
{
    pci_unregister_driver(&foo_driver);
    class_destroy(fooClass);
}