“设备没有释放()功能” - 这是什么意思?

时间:2013-03-20 18:47:16

标签: linux kernel driver

我正在尝试编写一个简单的Linux内核驱动程序,以便在加载模块时打开GPIO引脚。模块加载工作,但当我调用rmmod删除它时,我收到此错误:

sudo rmmod psctl
[13051.599199] ------------[ cut here ]------------
[13051.608758] WARNING: at drivers/base/core.c:196 device_release+0x78/0x84()
[13051.620581] Device 'psctl.0' does not have a release() function, it is broken and must be fixed.
[13051.637898] Modules linked in: psctl(O-) tmp102 hwmon nfsd rtc_ds1307 i2c_dev snd_bcm2835 snd_pcm snd_page_alloc snd_seq snd_seq_device snd_timer snd spidev leds_gpio led_class spi_bcm2708 i2c_bcm2708 [last unloaded: psctl]
[13051.670268] [<c0013f64>] (unwind_backtrace+0x0/0xf0) from [<c001e80c>] (warn_slowpath_common+0x4c/0x64)
[13051.688743] [<c001e80c>] (warn_slowpath_common+0x4c/0x64) from [<c001e8b8>] (warn_slowpath_fmt+0x30/0x40)
[13051.707217] [<c001e8b8>] (warn_slowpath_fmt+0x30/0x40) from [<c0239240>] (device_release+0x78/0x84)
[13051.725132] [<c0239240>] (device_release+0x78/0x84) from [<c01f4ad8>] (kobject_release+0x50/0x84)
[13051.742880] [<c01f4ad8>] (kobject_release+0x50/0x84) from [<bf0e6064>] (gpiotest_exit+0x10/0x2c [psctl])
[13051.761326] [<bf0e6064>] (gpiotest_exit+0x10/0x2c [psctl]) from [<c005e140>] (sys_delete_module+0x1b4/0x240)
[13051.780050] [<c005e140>] (sys_delete_module+0x1b4/0x240) from [<c000dae0>] (ret_fast_syscall+0x0/0x30)
[13051.798205] ---[ end trace 2eaa6df2dbf1f2e2 ]---
[13051.810083] psctl: Unloaded module

这是什么意思?我已经看过drivers / base / core.c,看起来kobject或kobj_type都没有与它们相关的释放方法(或者kobj上没有设置kobj_type)。我本来应该自己设置发布方法,还是还有其他我没做过的事情会为我设置这个?

该模块的代码如下:

    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/slab.h>
    #include <linux/device.h>
    #include <linux/types.h>
    #include <linux/fs.h>
    #include <linux/platform_device.h>

    #define AUTHOR "Xian Stannard <xian@xianic.net>"
    #define DESCRIPTION "Simple GPIO driver as proof of concept"
    #define VERSION "0.1"
    #define DRIVER_NAME "psctl"
    #define OUT_GPIO 18

    #define MPRINT(level, fmt, args...) printk(level DRIVER_NAME ": " fmt "\n", ## args)

    struct ps_data_struct {
        int out_gpio;
    };

    static int ps_probe(struct platform_device *pdev) {
        struct ps_data_struct *data = pdev->dev.platform_data;

        if(data == NULL)
            MPRINT(KERN_DEBUG, "No platform data");
        else {
            MPRINT(KERN_DEBUG, "Has platform data: gpio %d", data->out_gpio);
        }

        return -ENODEV;
    }

    static int __exit ps_remove(struct platform_device *dev) {
        MPRINT(KERN_DEBUG, "Remove");
        return 0;
    }

    static void ps_release(struct device* dev) {
        MPRINT(KERN_DEBUG, "Release");
    }

    static struct ps_data_struct ps_data = {
        .out_gpio = OUT_GPIO
    };

    static struct platform_driver ps_driver = {
        .driver = {
            .name = DRIVER_NAME,
            .owner = THIS_MODULE
        },
        .probe = ps_probe,
        .remove = __exit_p(ps_remove)
    };

    static struct platform_device ps_device = {
        .name = DRIVER_NAME,
        .id = 0,
        .dev = {
            .platform_data = &ps_data
        }
    };

    static int __init gpiotest_init(void) {
        int retval = 0;

        retval = platform_driver_register(&ps_driver);
        if(retval != 0) {
            MPRINT(KERN_ERR, "Could not register driver");
            goto drvreg;
        }

        retval = platform_device_register(&ps_device);
        if(retval != 0) {
            MPRINT(KERN_ERR, "Could not create device");
            goto devreg;
        }

        MPRINT(KERN_INFO, "Loaded module");
        return 0;

    devreg:
        platform_driver_unregister(&ps_driver);

    drvreg:
        MPRINT(KERN_ERR, "Module load failed with error code %d", retval);
        return retval;
    }

    static void __exit gpiotest_exit(void) {
        platform_device_unregister(&ps_device);
        platform_driver_unregister(&ps_driver);
        MPRINT(KERN_INFO, "Unloaded module");
    }

    module_init(gpiotest_init);
    module_exit(gpiotest_exit);

    MODULE_AUTHOR(AUTHOR);
    MODULE_DESCRIPTION(DESCRIPTION);
    MODULE_VERSION(VERSION);
    MODULE_LICENSE("GPL");

2 个答案:

答案 0 :(得分:5)

我认为使用platform_device_register()注册设备时,pdev->dev->release未初始化,因此当您尝试删除此设备时,会打印出OOPS消息。 有两种解决方案可以解决这个问题:

  1. 使用platform_device_alloc()platform_device_add()注册您的设备;

  2. 如果您坚持使用ps_device.dev.release,请自行初始化platform_device_register()

答案 1 :(得分:0)

调用platform_device_alloc()以获取设备实例时,release方法的初始化已对默认函数完成,如here所示。

struct platform_device *platform_device_alloc(const char *name, int id)
{
    ...
    ...
    pa->pdev.dev.release = platform_device_release;
    ...
    ...
}

这是the default implementation of platform_device_release

但是,当您避免使用platform_device_alloc时,您显然会错过此初始化,因此需要为设备提供自己的release方法的实现。