自動建立裝置節點 ,手動建立…
阿新 • • 發佈:2019-02-20
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這個裝置節點了。
mdev是busybox自帶的一個簡化版的udev,適合於嵌入式的應用埸合。其具有使用簡單的特點。它的作用,就是在系統啟動和熱插拔 或動態載入驅動程式時,自動產生驅動程式所需的節點檔案。在以busybox為基礎構建嵌入式linux的根檔案系統時,使用它是最優
的選擇。
mdev使用
mdev的使用在busybox中的mdev.txt文件已經將得很詳細了。但作為例子,我簡單講講我的使用過程:
(1)在編譯時加上對mdev的支援(我是使用的是busybox1.10.1):
Linux System Utilities --->
mdev
Support /etc/mdev.conf
Support command execution at device addition/removal
(2)在啟動時加上使用mdev的命令:
我在自己建立的根檔案系統(nfs)中的/linuxrc檔案中添加了如下指令:
#掛載/sys為sysfs檔案系統
echo "----------mount /sys as sysfs"
/bin/mount -t tmpfs mdev /dev
/bin/mount -t sysfs sysfs /sys
echo "----------Starting mdev......"
/bin/echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
注意:是/bin/echo /sbin/mdev > /proc/sys/kernel/hotplug,並非/bin/echo /bin/mdev > /proc/sys/kernel/hotplug。
busybox的文件有錯!!
(3)在你的驅動中加上對類裝置介面的支援。
在驅動程式的初始化函式中,使用下述的類似語句,就能在類裝置目錄下新增包含裝置號的名為“dev”的屬性檔案。並通過mdev
在/dev目錄下產生gpio_dev0的裝置節點檔案。
my_class = class_create(THIS_MODULE, "gpio_class");
if(IS_ERR(my_class)) {
printk("Err: failed in creating class.\n");
return -1;
}
class_device_create(my_class, NULL, MKDEV(gpio_major_number, 0), NULL, "gpio_dev%d" ,0);
在驅動程式的清除程式段,加入以下語句,以完成清除工作。
class_device_destroy(my_class, MKDEV(gpio_major_number, 0));
class_destroy(my_class);
需要的標頭檔案是linux/device.h,因此程式的開始應加入下句
#include
另外,my_class是class型別的結構體指標,要在程式開始時宣告成全域性變數。
struct class *my_class;
上述程式中的gpio_major_number是裝置的主節點號。可以換成需要的節點號。gpio_dev是最終生成的裝置節點檔案的名子。%d是
用於以相同裝置自動編號的。gpio_class是建立的class的名稱,當驅動程式載入後,可以在/sys/class的目錄下看到它。
上述語句也不一定要在初始化和清除階段使用,可以根據需要在其它地方使用。
(4)至於/etc/mdev.conf檔案,可有可無,不影響使用,只是添加了些功能。
關於mdev的使用方法,我在網上找到一篇中文版的。大家可以到我上傳的資源中下載。
要想真正用好mdev,適當知道一下原理是必不可少的。現在簡單介紹一下mdev的原理:
執行mdev -s
:以‘-s’為引數呼叫位於
/sbin目錄寫的mdev(其實是個連結,作用是傳遞引數給/bin目錄下的busybox程式並呼叫它),mdev掃描 /sys/class 和
/sys/block
中所有的類裝置目錄,如果在目錄中含有名為“dev”的檔案,且檔案中包含的是裝置號,則mdev就利用這些資訊為這個裝置在/dev
下建立裝置節點檔案。一般只在啟動時才執行一次 “mdev -s”。
熱插拔事件:由於啟動時運行了命
令:echo /sbin/mdev > /proc/sys/kernel/hotplug ,那麼當有熱插拔事件產生時,核心就會呼叫位於
/sbin目錄的mdev。這時mdev通過環境變數中的 ACTION 和
DEVPATH,(這兩個變數是系統自帶的)來確定此次熱插拔事件的動作以及影響了/sys中的那個目錄。接著會看看這個目錄中是否有
“dev”的屬性檔案,如果有就利用這些資訊為
這個裝置在/dev 下建立裝置節點檔案。
最後,附上我在工作中編寫的一段簡單的gpio控制驅動程式。此程式沒有什麼功能,主要是做一些測試用的。有興趣的朋友可以用
它測試一下上述的mdev的使用方法。我用的是友善公司的mini2440開發板。
補充:1
[b]為mdev的執行準備環境
mdev需要改寫/dev和/sys兩個目錄。所以必須保證這兩個目錄是可寫的(一般會用到sysfs,tmpfs。所以要重新編譯核心)。
然後在你的啟動指令碼檔案中加入
/bin/mdev -s[/b]
[b]補充2:[/b]
[b] ·/etc/fstab[/b]
[b]這是mount -a要讀取的文字。根據需要編寫。[/b]
這個程式碼在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 ,因為定義這些函式是在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
- #include
- #include
- #include
- #include
- #include
- 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
- };
- staticvoid 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);
- }
- structclass *my_class;
- staticint __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 ();
- my_class = class_create(THIS_MODULE, "my_class");
- if(IS_ERR(my_class))
- {
- printk("Err: failed in creating class./n");
- return -1;
- }
- device_create( my_class, NULL, MKDEV(hello_major, 0), "hello""%d", 0 );
- printk (KERN_INFO "Registered character driver/n");
- return 0;
- }
- staticvoid __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這個裝置節點了。
mdev是busybox自帶的一個簡化版的udev,適合於嵌入式的應用埸合。其具有使用簡單的特點。它的作用,就是在系統啟動和熱插拔 或動態載入驅動程式時,自動產生驅動程式所需的節點檔案。在以busybox為基礎構建嵌入式linux的根檔案系統時,使用它是最優
的選擇。
mdev使用
mdev的使用在busybox中的mdev.txt文件已經將得很詳細了。但作為例子,我簡單講講我的使用過程:
(1)在編譯時加上對mdev的支援(我是使用的是busybox1.10.1):
Linux System Utilities --->
mdev
Support /etc/mdev.conf
Support command execution at device addition/removal
(2)在啟動時加上使用mdev的命令:
我在自己建立的根檔案系統(nfs)中的/linuxrc檔案中添加了如下指令:
#掛載/sys為sysfs檔案系統
echo "----------mount /sys as sysfs"
/bin/mount -t tmpfs mdev /dev
/bin/mount -t sysfs sysfs /sys
echo "----------Starting mdev......"
/bin/echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
注意:是/bin/echo /sbin/mdev > /proc/sys/kernel/hotplug,並非/bin/echo /bin/mdev > /proc/sys/kernel/hotplug。
busybox的文件有錯!!
(3)在你的驅動中加上對類裝置介面的支援。
在驅動程式的初始化函式中,使用下述的類似語句,就能在類裝置目錄下新增包含裝置號的名為“dev”的屬性檔案。並通過mdev
在/dev目錄下產生gpio_dev0的裝置節點檔案。
my_class = class_create(THIS_MODULE, "gpio_class");
if(IS_ERR(my_class)) {
printk("Err: failed in creating class.\n");
return -1;
}
class_device_create(my_class, NULL, MKDEV(gpio_major_number, 0), NULL, "gpio_dev%d" ,0);
在驅動程式的清除程式段,加入以下語句,以完成清除工作。
class_device_destroy(my_class, MKDEV(gpio_major_number, 0));
class_destroy(my_class);
需要的標頭檔案是linux/device.h,因此程式的開始應加入下句
#include
另外,my_class是class型別的結構體指標,要在程式開始時宣告成全域性變數。
struct class *my_class;
上述程式中的gpio_major_number是裝置的主節點號。可以換成需要的節點號。gpio_dev是最終生成的裝置節點檔案的名子。%d是
用於以相同裝置自動編號的。gpio_class是建立的class的名稱,當驅動程式載入後,可以在/sys/class的目錄下看到它。
上述語句也不一定要在初始化和清除階段使用,可以根據需要在其它地方使用。
(4)至於/etc/mdev.conf檔案,可有可無,不影響使用,只是添加了些功能。
關於mdev的使用方法,我在網上找到一篇中文版的。大家可以到我上傳的資源中下載。
要想真正用好mdev,適當知道一下原理是必不可少的。現在簡單介紹一下mdev的原理:
執行mdev -s
:以‘-s’為引數呼叫位於
/sbin目錄寫的mdev(其實是個連結,作用是傳遞引數給/bin目錄下的busybox程式並呼叫它),mdev掃描 /sys/class 和
/sys/block
中所有的類裝置目錄,如果在目錄中含有名為“dev”的檔案,且檔案中包含的是裝置號,則mdev就利用這些資訊為這個裝置在/dev
下建立裝置節點檔案。一般只在啟動時才執行一次 “mdev -s”。
熱插拔事件:由於啟動時運行了命
令:echo /sbin/mdev > /proc/sys/kernel/hotplug ,那麼當有熱插拔事件產生時,核心就會呼叫位於
/sbin目錄的mdev。這時mdev通過環境變數中的 ACTION 和
DEVPATH,(這兩個變數是系統自帶的)來確定此次熱插拔事件的動作以及影響了/sys中的那個目錄。接著會看看這個目錄中是否有
“dev”的屬性檔案,如果有就利用這些資訊為
這個裝置在/dev 下建立裝置節點檔案。
最後,附上我在工作中編寫的一段簡單的gpio控制驅動程式。此程式沒有什麼功能,主要是做一些測試用的。有興趣的朋友可以用
它測試一下上述的mdev的使用方法。我用的是友善公司的mini2440開發板。
補充:1
[b]為mdev的執行準備環境
mdev需要改寫/dev和/sys兩個目錄。所以必須保證這兩個目錄是可寫的(一般會用到sysfs,tmpfs。所以要重新編譯核心)。
然後在你的啟動指令碼檔案中加入
/bin/mdev -s[/b]
[b]補充2:[/b]
[b] ·/etc/fstab[/b]
[b]這是mount -a要讀取的文字。根據需要編寫。[/b]