自动创建设备节点
創建設備文件的方法:
第一種:使用mknod手工創建,mknod filename type major minor
第二種:自動創建設備節點,利用udev來實現設備文件的自動創建
?
udev介紹
udev 運行在用戶模式,而非內核中。udev 的初始化腳本在系統啟動時創建設備節點,并且當插入新設備——加入驅動模塊——在sysfs上注冊新的數據后,udev會創建新的設備節點。
udev 是一個工作在用戶空間的工具,它能根據系統中硬件設備的狀態動態的更新設備文件,包括設備文件的創建,刪除,權限等。這些文件通常都定義在/dev 目錄下,但也可以在配置文件中指定。udev 必須內核中的sysfs和tmpfs支持,sysfs 為udev 提供設備入口和uevent 通道,tmpfs 為udev 設備文件提供存放空間。
注意,udev 是通過對內核產生的設備文件修改,或增加別名的方式來達到自定義設備文件的目的。但是,udev 是用戶模式程序,其不會更改內核行為。也就是說,內核仍然會創建sda,sdb等設備文件,而udev可根據設備的唯一信息來區分不同的設備,并產生新的設備文件(或鏈接)。而在用戶的應用中,只要使用新產生的設備文件
?
自動創建設備節點:
在驅動用加入對udev 的支持主要做的就是:在驅動初始化的代碼里調用class_create(...)為該設備創建一個class,再為每個設備調用device_create(...)創建對應的設備。
內核中定義的struct class結構體,顧名思義,一個struct class結構體類型變量對應一個類,內核同時提供了class_create(…)函數,可以用它來創建一個類,這個類存放于sysfs下面,一旦創建好了這個類,再調用 device_create(…)函數來在/dev目錄下創建相應的設備節點。
這樣,加載模塊的時候,用戶空間中的udev會自動響應 device_create()函數,去/sysfs下尋找對應的類從而創建設備節點。
?
#include <linux/module.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/device.h>//#define MYMAJOR 200 #define MYCNT 1 #define MYNAME "testchar"static dev_t mydev; static struct cdev test_cdev; static struct class *test_class;static int test_chrdev_open(struct inode *inode, struct file *file) {printk(KERN_INFO "test_chrdev_open...\n");return 0; }static int test_chrdev_release(struct inode *inode, struct file *file) {printk(KERN_INFO "test_chrdev_release...\n");return 0; }ssize_t test_chrdev_read(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) {printk(KERN_INFO "test_chrdev_read...\n");return 0; }static ssize_t test_chrdev_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) {printk(KERN_INFO "test_chrdev_write...\n");return 0; }static const struct file_operations test_fops = {.owner = THIS_MODULE,.open = test_chrdev_open,.release = test_chrdev_release,.write = test_chrdev_write,.read = test_chrdev_read, };static int __init chrdev_init(void) { int retval;printk(KERN_INFO "chrdev_init...\n");/* 分配主次設備號 */ /*mydev = MKDEV(MYMAJOR, 0);retval = register_chrdev_region(mydev, MYCNT, MYNAME);if (retval) {printk(KERN_ERR "Unable to register minors for %s\n", MYNAME);return -EINVAL;} */retval = alloc_chrdev_region(&mydev, 12, MYCNT, MYNAME);if (retval < 0) {printk(KERN_ERR "Unable to alloc minors for %s\n", MYNAME);goto flag1;}printk(KERN_INFO "alloc_chrdev_region success\n");printk(KERN_INFO "major = %d, minor = %d.\n", MAJOR(mydev), MINOR(mydev));/* 注冊字符設備驅動 */cdev_init(&test_cdev, &test_fops);retval = cdev_add(&test_cdev, mydev, MYCNT);if (retval) {printk(KERN_ERR "Unable to cdev_add\n");goto flag2;}printk(KERN_INFO "cdev_add success\n");/* 創建設備類 */test_class = class_create(THIS_MODULE, "test_class");if (IS_ERR(test_class)) {printk(KERN_ERR "Unable to class_create\n");goto flag3;}/* 創建設備節點 */device_create(test_class, NULL, mydev, NULL, "test");return 0;flag3:cdev_del(&test_cdev);flag2:unregister_chrdev_region(mydev, MYCNT); flag1: return -EINVAL; }static void __exit chrdev_exit(void) {printk(KERN_INFO "chrdev_exit...\n");/* 銷毀設備類節點 */device_destroy(test_class, mydev);class_destroy(test_class);/* 注銷字符設備驅動 */cdev_del(&test_cdev);/* 注銷申請的主次設備號 */unregister_chrdev_region(mydev, MYCNT); }module_init(chrdev_init); module_exit(chrdev_exit);MODULE_LICENSE("GPL"); // 描述模塊的許可證 MODULE_AUTHOR("lsm"); // 描述模塊的作者 MODULE_DESCRIPTION("module test"); // 描述模塊的介紹信息 MODULE_ALIAS("alias xxx"); // 描述模塊的別名信息?
總結
- 上一篇: 大数据不背“杀熟”的锅!高科技公司掌握了
- 下一篇: Simulink之单管非隔离直流斩波器