我写了一个简单的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
答案 0 :(得分:5)
您应至少打印错误编号以了解原因。
pr_err("%s:%d error code %d\n", __func__, __LINE__, PTR_ERR(foo_dev->dev));
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);
}