在Linux上为一个简单的char驱动程序在device_create()上失败

lor*_*zli 7 c linux kernel linux-device-driver linux-kernel

我写了一个简单的char驱动程序,现在想要使用类在udev中自动注册它.我的代码由以下部分组成init,当驱动程序被加载并调用函数probe时加载驱动程序的设备(当然,他们的反等价调用的函数exitremove).问题:添加新设备后,我的probe功能在执行device_create命令时失败.现在我想知道为什么:

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

根据我的代码,我删除了大多数返回验证(如IS_ERR())和清理函数以便于阅读.这两个变量是全局定义的:

static int foo_majNbr;
static struct class *fooClass;
Run Code Online (Sandbox Code Playgroud)

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

    ...
}
Run Code Online (Sandbox Code Playgroud)

probe功能:

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

    ...
}
Run Code Online (Sandbox Code Playgroud)

Fed*_*ico 5

您应该至少打印错误号以了解原因.

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

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

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

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