自動建立裝置節點 device_create
阿新 • • 發佈:2019-02-18
error: implicit declaration of ‘class_device_create’
這個程式碼在Kernel 2.6.18下面編譯的時候沒有任何問題。為什麼在2.6.34下面會出現這個錯誤呢?難道class_device_create這個kernel API已經從新版kernel裡面移除了?
google了一下,發現確實是已經被移除了,在新版的kernel裡面,可以使用device_create來代替,引數完全一致。
在LXR(http://lxr.linux.no)網站上面查找了一番,發現class_device_create在2.6.25裡面還有,從2.6.26起就被移除了。
Linux Kernel的Kernel API是經常會變化的。這給需要支援多個版本的Driver帶來了不小的麻煩。有沒有什麼地方可以很方便的知道 Linux Kernel各個版本之間Kernel API的變化?暫時沒有找到。一個可行的方法是,遇到問題之後,到LXR裡面如搜尋一下,LXR可以搜尋特定的kernel版本。
在2.4裡裝置檔案採用的是devfs,在2.6裡已經用udev取代devfs,為解決上面那樣手動建立節點的麻煩,我們可以在程式里加上建立節點這項,如下: 以字元裝置char_dev為例,在驅動初始化的程式碼裡呼叫class_create為該裝置建立一個class,再為每個裝置呼叫 class_device_create建立對應的裝置,這樣的module被載入時,undev daemon就會自動在/dev下建立char_dev裝置檔案。大概方法如下:
struct class *myclass = class_create(THIS_MODULE, “char_dev”);
class_device_create(myclass, NULL, MKDEV(major_num, 0), NULL, “char_dev”);
這樣,模組載入後,就能在/dev目錄下找到hello0這個裝置節點了。
這個程式碼在Kernel 2.6.18下面編譯的時候沒有任何問題。為什麼在2.6.34下面會出現這個錯誤呢?難道class_device_create這個kernel API已經從新版kernel裡面移除了?
google了一下,發現確實是已經被移除了,在新版的kernel裡面,可以使用device_create來代替,引數完全一致。
在LXR(http://lxr.linux.no)網站上面查找了一番,發現class_device_create在2.6.25裡面還有,從2.6.26起就被移除了。
Linux Kernel的Kernel API是經常會變化的。這給需要支援多個版本的Driver帶來了不小的麻煩。有沒有什麼地方可以很方便的知道 Linux Kernel各個版本之間Kernel API的變化?暫時沒有找到。一個可行的方法是,遇到問題之後,到LXR裡面如搜尋一下,LXR可以搜尋特定的kernel版本。
之前寫的字元類裝置驅動,沒有自動建立裝置節點,因為只使用了register_chrdev()函式,只是註冊了這個裝置。然後在系統啟動後,就要自己建立裝置節點mknod,這樣雖然是可行的,但是比較麻煩。於是想在__init函式裡面,自動建立裝置節點。
經過查閱資料,發現建立裝置節點使用了兩個函式 class_create()和class_device_create(),當然在__exit()函式裡,要使用class_destory()和class_device_desotry()登出建立的裝置節點!
問題來了,編譯了之後,發現報錯error: implicit declaration of 'class_device_create'等幾個錯誤。經過分析,應該是Linux核心版本不同的原因!早期的版本,使用的是上面說的兩個函式,但是在2.6.29以後(我用的是2.6.32的),使用的函式則變成了 class_create()和device_create(),並且要在宣告中加入#i nclude <linux/device.h> ,因為定義這些函式是在Linux2.6.32/include/linux/device.h裡面!
經過這些修改後,驅動編譯成功,就能夠自動建立裝置節點了!
自學驅動以來,一直都是在載入模組後採用手動建立節點,雖然這個過程比較簡單,畢竟還是有點麻煩,尤其是在除錯模組的時候。 #insmod module_name.ko #mknod /dev/module_name c MAJOR MINOR #在2.4裡裝置檔案採用的是devfs,在2.6裡已經用udev取代devfs,為解決上面那樣手動建立節點的麻煩,我們可以在程式里加上建立節點這項,如下: 以字元裝置char_dev為例,在驅動初始化的程式碼裡呼叫class_create為該裝置建立一個class,再為每個裝置呼叫 class_device_create建立對應的裝置,這樣的module被載入時,undev daemon就會自動在/dev下建立char_dev裝置檔案。大概方法如下:
struct class *myclass = class_create(THIS_MODULE, “char_dev”);
class_device_create(myclass, NULL, MKDEV(major_num, 0), NULL, “char_dev”);
當然,在exit函式中要把建立的class移除:
class_destory(&xxx_dev->cdev);
class_device_desotry(my_class,MKDEV(major_num,0));
下面以一個簡單字元裝置驅動來展示如何使用這幾個函式
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
MODULE_LICENSE ("GPL");
int hello_major = 555;
int hello_minor = 0;
int number_of_devices = 1;
struct cdev cdev;
dev_t dev = 0;
struct file_operations hello_fops = {
.owner = THIS_MODULE
};
static void char_reg_setup_cdev (void)
{
int error, devno = MKDEV (hello_major, hello_minor);
cdev_init (&cdev, &hello_fops);
cdev.owner = THIS_MODULE;
cdev.ops = &hello_fops;
error = cdev_add (&cdev, devno , 1);
if (error)
printk (KERN_NOTICE "Error %d adding char_reg_setup_cdev", error);
}
struct class *my_class;
static int __init hello_2_init (void)
{
int result;
dev = MKDEV (hello_major, hello_minor);
result = register_chrdev_region (dev, number_of_devices, "hello");
if (result<0) {
printk (KERN_WARNING "hello: can't get major number %d/n", hello_major);
return result;
}
char_reg_setup_cdev ();
/* create your own class under /sysfs */
my_class = class_create(THIS_MODULE, "my_class");
if(IS_ERR(my_class))
{
printk("Err: failed in creating class./n");
return -1;
}
/* register your own device in sysfs, and this will cause udev to create corresponding device node */
device_create( my_class, NULL, MKDEV(hello_major, 0), "hello" "%d", 0 );
printk (KERN_INFO "Registered character driver/n");
return 0;
}
static void __exit hello_2_exit (void)
{
dev_t devno = MKDEV (hello_major, hello_minor);
cdev_del (&cdev);
device_destroy(my_class, MKDEV(adc_major, 0)); //delete device node under /dev
class_destroy(my_class); //delete class created by us
unregister_chrdev_region (devno, number_of_devices);
printk (KERN_INFO "char driver cleaned up/n");
}
module_init (hello_2_init);
module_exit (hello_2_exit);
這樣,模組載入後,就能在/dev目錄下找到hello0這個裝置節點了。