十五、linux 注册字符类设备和生成节点
一、?注冊字符類設備
? 分配內存空間函數kmalloc
????????– 分配連續的虛擬地址,用于小內存分配。在include/linux/slab.h文件中。
????????– 參數1:申請的內存大小(最大128K),
????????– 參數2:GFP_KERNEL,代表優先權,內存不夠可以延遲分配
? 清空內存空間的數據函數memset
????????– 可以清空內存空間,也就是全部寫為0
????????– 參數1:內存地址
????????– 參數2:0
????????– 參數3:內存長度
? 字符設備初始化函數cdev_init
????????– 在頭文件include/linux/cdev.h中
????????– 參數1:cdev字符設備文件結構體
????????– 參數2:file_operations結構體
????????– 注冊設備本質是向linux設備文件中添加數據,這些數據需要初始化
? 字符設備注冊函數cdev_add
????????– 在頭文件include/linux/cdev.h中
????????– 參數1:cdev字符設備文件結構體
????????– 參數2:設備號
????????– 參數3:設備范圍大小
????????– 向系統注冊設備,也就是向linux系統添加數據
? 卸載設備函數cdev_del
????????– 參數1:cdev結構體
????????– 移除字符設備
?二、生成字符類設備節點
? 函數class_create創建class類文件
????????– 參數1:一般是THIS_MODULE
????????– 參數2:設備名稱
????????– 創建一個設備類,用于設備節點文件的創建
????????– 返回一個class結構體變量
? class結構體變量
????????– class是設備驅動模型中通用的設備類結構
????????– 在頭文件include/linux/device.h的280行
? 創建設備節點函數device_create
????????– 頭文件include/linux/device.h中
????????– 參數1:設備所屬于的類
????????– 參數2:設備的父設備,NULL
????????– 參數3:設備號
????????– 參數4:設備數據,NULL
????????– 參數4:設備名稱
? 摧毀設備節點函數device_destroy
????????– 參數1:設備所屬于的類
????????– 參數2:設備號
? 老版本:創建設備class函數class_device_create(已作廢)
????????– 頭文件include/linux/device.h中
????????– 參數1:class結構體變量
????????– 參數2:父設備NULL
????????– 參數3:dev_t設備號
????????– 參數4:數據NULL
????????– 參數5:設備節點名稱
? 釋放設備class函數class_destroy(已作廢)
????????– 參數1:myclass
三、代碼
/*包含初始化宏定義的頭文件,代碼中的module_init和module_exit在此文件中*/ #include <linux/init.h> /*包含初始化加載模塊的頭文件,代碼中的MODULE_LICENSE在此頭文件中*/ #include <linux/module.h> /*定義module_param module_param_array的頭文件*/ #include <linux/moduleparam.h> /*定義module_param module_param_array中perm的頭文件*/ #include <linux/stat.h> /*三個字符設備函數*/ #include <linux/fs.h> /*MKDEV轉換設備號數據類型的宏定義*/ #include <linux/kdev_t.h> /*定義字符設備的結構體*/ #include <linux/cdev.h> /*分配內存空間函數頭文件*/ #include <linux/slab.h>/*包含函數device_create 結構體class等頭文件*/ #include <linux/device.h>#define DEVICE_NAME "chardevnode" #define DEVICE_MINOR_NUM 2 #define DEV_MAJOR 0 #define DEV_MINOR 0 #define REGDEV_SIZE 3000MODULE_LICENSE("Dual BSD/GPL"); /*聲明是開源的,沒有內核版本限制*/ MODULE_AUTHOR("iTOPEET_dz"); /*聲明作者*/int numdev_major = DEV_MAJOR; int numdev_minor = DEV_MINOR;/*輸入主設備號*/ module_param(numdev_major,int,S_IRUSR); /*輸入次設備號*/ module_param(numdev_minor,int,S_IRUSR);static struct class *myclass;struct reg_dev {char *data;unsigned long size;struct cdev cdev; }; struct reg_dev *my_devices;struct file_operations my_fops = {.owner = THIS_MODULE, };/*設備注冊到系統*/ static void reg_init_cdev(struct reg_dev *dev,int index){int err;int devno = MKDEV(numdev_major,numdev_minor+index);/*數據初始化*/cdev_init(&dev->cdev,&my_fops);dev->cdev.owner = THIS_MODULE;dev->cdev.ops = &my_fops;/*注冊到系統*/err = cdev_add(&dev->cdev,devno,1);if(err){printk(KERN_EMERG "cdev_add %d is fail! %d\n",index,err);}else{printk(KERN_EMERG "cdev_add %d is success!\n",numdev_minor+index);} }static int scdev_init(void) {int ret = 0,i;dev_t num_dev;printk(KERN_EMERG "numdev_major is %d!\n",numdev_major);printk(KERN_EMERG "numdev_minor is %d!\n",numdev_minor);if(numdev_major){num_dev = MKDEV(numdev_major,numdev_minor);ret = register_chrdev_region(num_dev,DEVICE_MINOR_NUM,DEVICE_NAME); // 靜態注冊設備號}else{/*動態注冊設備號*/ret = alloc_chrdev_region(&num_dev,numdev_minor,DEVICE_MINOR_NUM,DEVICE_NAME);/*獲得主設備號*/numdev_major = MAJOR(num_dev);printk(KERN_EMERG "adev_region req %d !\n",numdev_major);}if(ret<0){printk(KERN_EMERG "register_chrdev_region req %d is failed!\n",numdev_major); }myclass = class_create(THIS_MODULE,DEVICE_NAME); // 創建class類 “ls /sys/class/”查看my_devices = kmalloc(DEVICE_MINOR_NUM * sizeof(struct reg_dev),GFP_KERNEL); // 申請內存空間if(!my_devices){ret = -ENOMEM;goto fail;}memset(my_devices,0,DEVICE_MINOR_NUM * sizeof(struct reg_dev));/*設備初始化*/for(i=0;i<DEVICE_MINOR_NUM;i++){my_devices[i].data = kmalloc(REGDEV_SIZE,GFP_KERNEL); // 申請設備數據空間memset(my_devices[i].data,0,REGDEV_SIZE);/*設備注冊到系統*/reg_init_cdev(&my_devices[i],i); /*創建設備節點*/device_create(myclass,NULL,MKDEV(numdev_major,numdev_minor+i),NULL,DEVICE_NAME"%d",i); // “ls /dev”查看}printk(KERN_EMERG "scdev_init!\n");/*打印信息,KERN_EMERG表示緊急信息*/return 0;fail:/*注銷設備號*/unregister_chrdev_region(MKDEV(numdev_major,numdev_minor),DEVICE_MINOR_NUM);printk(KERN_EMERG "kmalloc is fail!\n");return ret; }static void scdev_exit(void) {int i;printk(KERN_EMERG "scdev_exit!\n");/*除去字符設備*/for(i=0;i<DEVICE_MINOR_NUM;i++){cdev_del(&(my_devices[i].cdev));/*摧毀設備節點函數d*/device_destroy(myclass,MKDEV(numdev_major,numdev_minor+i));kfree(my_devices[i].data);}/*釋放設備class*/class_destroy(myclass);/*釋放內存*/kfree(my_devices);unregister_chrdev_region(MKDEV(numdev_major,numdev_minor),DEVICE_MINOR_NUM); }module_init(scdev_init); /*初始化函數*/ module_exit(scdev_exit); /*卸載函數*/四、運行
?
?
總結
以上是生活随笔為你收集整理的十五、linux 注册字符类设备和生成节点的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 十四、linux 静态/动态申请字符设备
- 下一篇: 交叉编译器 arm-linux-gnue