自动创建设备节点
創(chuàng)建設(shè)備文件的方法:
第一種:使用mknod手工創(chuàng)建,mknod filename type major minor
第二種:自動創(chuàng)建設(shè)備節(jié)點,利用udev來實現(xiàn)設(shè)備文件的自動創(chuàng)建
?
udev介紹
udev 運行在用戶模式,而非內(nèi)核中。udev 的初始化腳本在系統(tǒng)啟動時創(chuàng)建設(shè)備節(jié)點,并且當(dāng)插入新設(shè)備——加入驅(qū)動模塊——在sysfs上注冊新的數(shù)據(jù)后,udev會創(chuàng)建新的設(shè)備節(jié)點。
udev 是一個工作在用戶空間的工具,它能根據(jù)系統(tǒng)中硬件設(shè)備的狀態(tài)動態(tài)的更新設(shè)備文件,包括設(shè)備文件的創(chuàng)建,刪除,權(quán)限等。這些文件通常都定義在/dev 目錄下,但也可以在配置文件中指定。udev 必須內(nèi)核中的sysfs和tmpfs支持,sysfs 為udev 提供設(shè)備入口和uevent 通道,tmpfs 為udev 設(shè)備文件提供存放空間。
注意,udev 是通過對內(nèi)核產(chǎn)生的設(shè)備文件修改,或增加別名的方式來達(dá)到自定義設(shè)備文件的目的。但是,udev 是用戶模式程序,其不會更改內(nèi)核行為。也就是說,內(nèi)核仍然會創(chuàng)建sda,sdb等設(shè)備文件,而udev可根據(jù)設(shè)備的唯一信息來區(qū)分不同的設(shè)備,并產(chǎn)生新的設(shè)備文件(或鏈接)。而在用戶的應(yīng)用中,只要使用新產(chǎn)生的設(shè)備文件
?
自動創(chuàng)建設(shè)備節(jié)點:
在驅(qū)動用加入對udev 的支持主要做的就是:在驅(qū)動初始化的代碼里調(diào)用class_create(...)為該設(shè)備創(chuàng)建一個class,再為每個設(shè)備調(diào)用device_create(...)創(chuàng)建對應(yīng)的設(shè)備。
內(nèi)核中定義的struct class結(jié)構(gòu)體,顧名思義,一個struct class結(jié)構(gòu)體類型變量對應(yīng)一個類,內(nèi)核同時提供了class_create(…)函數(shù),可以用它來創(chuàng)建一個類,這個類存放于sysfs下面,一旦創(chuàng)建好了這個類,再調(diào)用 device_create(…)函數(shù)來在/dev目錄下創(chuàng)建相應(yīng)的設(shè)備節(jié)點。
這樣,加載模塊的時候,用戶空間中的udev會自動響應(yīng) device_create()函數(shù),去/sysfs下尋找對應(yīng)的類從而創(chuàng)建設(shè)備節(jié)點。
?
#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");/* 分配主次設(shè)備號 */ /*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));/* 注冊字符設(shè)備驅(qū)動 */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");/* 創(chuàng)建設(shè)備類 */test_class = class_create(THIS_MODULE, "test_class");if (IS_ERR(test_class)) {printk(KERN_ERR "Unable to class_create\n");goto flag3;}/* 創(chuàng)建設(shè)備節(jié)點 */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");/* 銷毀設(shè)備類節(jié)點 */device_destroy(test_class, mydev);class_destroy(test_class);/* 注銷字符設(shè)備驅(qū)動 */cdev_del(&test_cdev);/* 注銷申請的主次設(shè)備號 */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"); // 描述模塊的別名信息?
總結(jié)
- 上一篇: 大数据不背“杀熟”的锅!高科技公司掌握了
- 下一篇: Simulink之单管非隔离直流斩波器