Linux 驅動框架---設備文件devfs

設備文件系統

Linux引入了虛擬文件系統,從而使設備的訪問能夠像訪問普通文件系統同樣。所以在內核中描述打開文件的數據inode中的rdev成員用來記錄設備文件對應到的設備號。設備文件也由一個對應的file_operations 數據對象,用來描述設備的操做接口。設備文件系統最先是採用devfs實現的,可是後來由於種種緣由在2.6之後的內核中已經將其廢棄而轉而使用udev,他來本質上是沒有區別都是在設備添加到系統中時在/dev目錄下產生設備文件(機制相同),可是不一樣的是策略devfs的策略是將設備文件的建立過程放在了內核空間,而udev的策略是由內核提供機制而用戶空間提供策略從而完成設備的建立,因此如今設備文件管理由兩個軟件可用分別是PC平臺上的udev和嵌入式平臺上的mdev。node


devfs

接口均已經廢棄,不在詳細探究。linux

devfs_handle_t devfs_mk_dir(devfs_handle_t dir,const char* name,void* info);
devfs_handle_t devfs_register(devfs_handle_t de,const char* name,unsigned int flag,uinsigned int major,unsigned int minor,umode_t mode,void* ops,void* info);
devfs_handle_t devfs_unregister(devfs_handle_t de);

udev(mdev)

與devfs不一樣udev徹底工做在用戶空間,而內核經過netlink機制將,設備添加過程的相關信息經過netlink發送到用戶空間的udev程序,netlink機制能夠不理解是一種特殊的socket進程通信方式,用戶空間的udev接收到設備添加的信息後將完成設備文件的建立和設備文件操做接口等相關的配置和初始化操做。進而用戶空間程序就能像訪問普通文件同樣訪問設備了。編程


關於file和inode數據結構在內核中的探究

比較好奇設備文件在被多個用戶進程打開後後續fops操做接口的file和inode是同一個仍是個進程單獨一個,由於file中還由一個private_data成員在驅動編程中是比較重要的因此接下來進行專門的驗證。
編寫一個虛擬的設備驅動以下數據結構

#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <asm/io.h>

//file open operation function 
static int char_drv_open(struct inode *inode , struct file *filp)
{
	printk(KERN_EMERG "inode:%08x file:%08x\n",inode,filp);
  printk(KERN_EMERG "private_data:%08x\n",filp->private_data);
  printk(KERN_EMERG "inode:%08x\n",inode);
  filp->private_data = 0x5A5A5A5A;
	return 0;
}
//file read operation function
static int char_drv_read(struct file *filp , char __user *buf , size_t cnt , loff_t *offt)
{
	return 0;
}
//file write operation function
static int char_drv_write(struct file *filp,const char __user *buf , size_t cnt , loff_t *offt)
{
	return 0;
}
//file close operation function
static int char_drv_release(struct inode *inode , struct file *filp)
{
	return 0;
}

//file operation function struct
static struct file_operations my_test_fop=
{
	.owner = THIS_MODULE,
	.open  = char_drv_open,
	.read  = char_drv_read,
	.write = char_drv_write,
	.release = char_drv_release 
	
};

/* 設備結構體 */
struct test_dev
{
	dev_t devid; /* 設備號 */
	struct cdev cdev; /* cdev */
	struct class *class; /* 類 */
	struct device *device; /* 設備 */
	int major; /* 主設備號 */
	int minor; /* 次設備號 */
};

#define NEWCHRLED_CNT 1 /* 設備號個數 */
#define NEWCHRLED_NAME "newchrdev" /* 名字 */

struct test_dev   test_char_dev;

//module init   function
static int __init char_drv_test_init(void)
{
	//same hardware init 
	
	//apply device num 
	alloc_chrdev_region(&test_char_dev.devid, 0, NEWCHRLED_CNT,NEWCHRLED_NAME);
	
	test_char_dev.major = MAJOR(test_char_dev.devid); /* 獲取主設備號 */
	test_char_dev.minor = MINOR(test_char_dev.devid); /* 獲取次設備號 */
	printk(KERN_EMERG "major:%d minor:%d\n",test_char_dev.major ,test_char_dev.minor);
 
	//init dev struct
	cdev_init(&test_char_dev.cdev,&my_test_fop);
	//add dev to system
	cdev_add(&test_char_dev.cdev ,test_char_dev.devid ,NEWCHRLED_CNT );
	
	//build class
	test_char_dev.class = class_create(THIS_MODULE,"test2");
	if (IS_ERR(test_char_dev.class)) 
	{
		return PTR_ERR(test_char_dev.class);
	}
	//build device
	test_char_dev.device = device_create(test_char_dev.class,NULL ,test_char_dev.devid,NULL,"test2");
	if (IS_ERR(test_char_dev.device)) 
	{
		return PTR_ERR(test_char_dev.device);
	}
	
	return 0;
}
//module uninstall   function
static void __exit char_drv_test_exit(void)
{
	/* 註銷字符設備 */
	cdev_del(&test_char_dev.cdev);
  /* 刪除 cdev */
	unregister_chrdev_region(test_char_dev.devid, NEWCHRLED_CNT);
	
	device_destroy(test_char_dev.class, test_char_dev.devid);
	
	class_destroy(test_char_dev.class);
}
//module function band
module_init(char_drv_test_init);
module_exit(char_drv_test_exit);

//license and author
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Smile");

編寫應用程序以下:app

#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(void)
{
	int fd = open("/dev/fileinode",O_RDWR);
	if(fd<0)
	{
		perror("open");
	}
	getc(stdin);
	return 0;
}

結論
通過實驗驗證,設備文件每打開一次,內核都會在內核空間建立file對象而inode是指向同一數據塊。具體輸出以下:socket

//安裝模塊
[  466.459870] major:250 minor:0
//第一次執行
[  534.073202] inode:f437da00 file:f02cea80
[  534.073205] private_data:00000000
[  534.073207] inode:f437da00
//第二次執行
[  548.632708] inode:f437da00 file:f02bd000
[  548.632712] private_data:00000000
[  548.632713] inode:f437da00
相關文章
相關標籤/搜索