2013-03-20 66 views
1

我正試圖編寫一個簡單的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 <[email protected]>" 
    #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"); 

回答

5

我認爲使用platform_device_register()註冊的設備時,pdev->dev->release沒有初始化,所以當你嘗試刪除該設備時,OOPS信息打印出來。 有兩個解決方案來解決這個問題:

  1. 使用platform_device_alloc()platform_device_add()註冊設備;如果你堅持使用platform_device_register(),你自己初始化ps_device.dev.release

+0

我去選項1,它運作良好。謝謝。 – 2013-03-23 16:38:04