在Linux上debugging一个简单的字符驱动程序在device_create()上失败

我写了一个简单的字符驱动程序,现在想在udev中使用类自动注册它。 我的代码由驱动程序加载时调用的init函数和驱动程序加载其设备时调用的probe函数组成(当然还有它们的等价的exitremove )。 问题:一旦添加新设备,执行device_create命令时,我的probefunction失败。 现在我想知道为什么:

我怎么能得到更多的信息,为什么这个命令失败(除了失败)? 缺less任何参数(比如我的全局声明fooClass是否存在问题,是否应该将其移至probe函数,而不是在我眼中做出反应,但在许多示例中显示)? 还是其他监督错误?

我的代码我剥离了大多数返回validation(如IS_ERR() )和清理function的可读性。 这两个variables是全局定义的:

 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); ... } 

probefunction:

 static int __devinit foo_probe(struct pci_dev *dev, const struct pci_device_id *devId) { struct foo_dev *foo_dev = 0; int rv = 0; /* Allocate memory in Kernel (for parameters) */ foo_dev = kzalloc(sizeof(*foo_dev), GFP_KERNEL); foo_dev->pci_dev = dev; pci_set_drvdata(dev, foo_dev); foo_dev->devNbr = MKDEV(foo_majNbr, 1); /* Add class to device */ foo_dev->dev = device_create(fooClass, NULL, foo_dev->devNbr, foo_dev, DEVICE_NAME); if (IS_ERR(foo_dev->dev)) { /* ----> INDICATES FAILURE HERE <---- */ } /* Add char device */ cdev_init(&foo_dev->cdev, &foo_fops); rv = cdev_add(&foo_dev->cdev, foo_dev->devNbr, 1); /* Enabling device */ rv = pci_enable_device(dev); ... } 

你至少应该打印错误号码来知道原因。

 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文件中,您可以找到最常见的错误。 如果这个错误代码不能帮助你,你可以去device_create()的源代码找出你的错误产生的地方,并理解为什么。

在调用之前也许还要打印device_create()device_create()

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

问题要求提供关于调试的信息,在前面的答案中已经很好地解释了。 为了完整起见,我想分享为什么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); }