Linux 内核 设备号和struct file_operartion的使用

1,设备号的注册方法总结:

获取设备号
1) 从设备号中提取major和minor
 MAJOR(dev_t dev);
MINOR(dev_t dev);
2) 通过major和minor构建设备号
MKDEV(int major,int minor);
注:上面只是构建设备号。并未注册
3),设备号的注册:
    模块加载函数通过 register_chrdev_region( ) 或 alloc_chrdev_region( )来静态或者动态获取设备号;
    注销设备号:void unregister_chrdev_region(dev_t from, unsigned count);
通过 cat /proc/devices可以查看申请到的设备名和设备号

2,我们来看看c_dev结构体吧:

cdev结构体:
struct cdev { 
    struct kobject kobj;                  //内嵌的内核对象.
    struct module *owner;                 //该字符设备所在的内核模块的对象指针.
    const struct file_operations *ops;    //该结构描述了字符设备所能实现的方法,是极为关键的一个结构体.
    struct list_head list;                //用来将已经向内核注册的所有字符设备形成链表.
    dev_t dev;                            //字符设备的设备号,由主设备号和次设备号构成.
    unsigned int count;                   //隶属于同一主设备号的次设备号的个数.
};

这篇文章我们主要来看看struct file_operations的使用吧:

1),使用mknod手工创建:mknod filename type major minor可以查看设备号信息。
2),现在在上面手工创建时,我们可以手建一个设备节点,那么我们如果想用代码实现呢!在我们创建设备号和注册设备号成功后,我们来创建一个设备节点吧,在/dev下面可见,我门需要了解下面这两个函数的使用了

devce_name = class_create(THIS_MODULE,DEVICE_NAME)  // 注册一个在/dev下面可见的device_name设备节点
device_create(device_name,NULL,MKDEV(major,minor),NULL,DEVICE_NAME,MINOR(dev))) //DEVICE_NAME是个取名的字符串
这样一来我们就可以直接用这个设备节点了,那么使用之后怎么删除呢!
//删除设备节点, device_destroy(devce_name ,MKDEV(device_major,0));
 //注销类   class_destroy(devce_name )

#include
#include
#include
#include

#include
MODULE_LICENSE("Dual BSD/GPL");

#define CHARDEVICIVEDRIVER_MAJOR 240
#define CHARDEVICIVEDRIVER_MINOR 0

#define CHARDEVICIVEDRIVER_COUNT 1

#define CHARDEVICIVEDRIVER_NAME "chardevicedriver"
#define CHARDEVICIVEDRIVER_CLASS_NAME "chardevicedriver_class"

static u32 chardevicedriver_major = CHARDEVICIVEDRIVER_MAJOR;
static u32 chardevicedriver_minor = CHARDEVICIVEDRIVER_MINOR;

static struct class *dev_class = NULL;
static struct device *dev_device = NULL;

static int chardevicedriver_open(struct inode* inode,struct file* file)
{
	printk("FILE = %s,FUNCTION = %s,LINE = %d\n",__FILE__,__FUNCTION__,__LINE__);
	return 0;
}

ssize_t chardevicedriver_read(struct file* file,char __user* buf,size_t count,loff_t* f_pos)
{
	printk("FILE = %s,FUNCTION = %s,LINE = %d\n",__FILE__,__FUNCTION__,__LINE__);
	return 0;
}

ssize_t chardevicedriver_write(struct file* file,const char __user* buf,size_t count,loff_t* f_pos)
{
	printk("FILE = %s,FUNCTION = %s,LINE = %d\n",__FILE__,__FUNCTION__,__LINE__);
	return 0;
}

long unlocked_chardevicedriver_ioctl(struct file* file,unsigned int cmd,unsigned long argc)
{
	printk("FILE = %s,FUNCTION = %s,LINE = %d\n",__FILE__,__FUNCTION__,__LINE__);
	return 0;
}

static int chardevicedriver_release(struct inode* inode,struct file* file)
{
	printk("FILE = %s,FUNCTION = %s,LINE = %d\n",__FILE__,__FUNCTION__,__LINE__);
	return 0;
}

static struct file_operations chardevicedriver_fops = {
	.owner = THIS_MODULE,
	.open = chardevicedriver_open,
	.read = chardevicedriver_read,
	.write = chardevicedriver_write,
	.unlocked_ioctl = unlocked_chardevicedriver_ioctl,
	.release = chardevicedriver_release,
};

static struct cdev chardevicedriver_cdev ;

static int __init chardevicedriver_init(void)
{
	int ret = -EFAULT;
	dev_t dev = 0; //设备号
	printk("function = %s,line = %d\n",__FUNCTION__,__LINE__);
	
	dev = MKDEV(CHARDEVICIVEDRIVER_MAJOR,CHARDEVICIVEDRIVER_MINOR);
	ret = register_chrdev_region(dev,CHARDEVICIVEDRIVER_COUNT,CHARDEVICIVEDRIVER_NAME);
	if(ret >0)
	{
		printk("register_chrdev_regin can't getr char device : major = %d,name = %s\n",\
		CHARDEVICIVEDRIVER_MAJOR,CHARDEVICIVEDRIVER_NAME);
		goto failure_register_chrdev;
	}
	printk("register_chrdev_regin  : major = %d,name = %s\n",\
		CHARDEVICIVEDRIVER_MAJOR,CHARDEVICIVEDRIVER_NAME);
		
	//create device class
	dev_class = class_create(THIS_MODULE,CHARDEVICIVEDRIVER_CLASS_NAME);
	if(IS_ERR(dev_class))
	{
		printk("class_create failure\n");
		ret = PTR_ERR(dev_class);
		goto failure_create_class;
	}
	printk("chardevicedriver:success create class:CHARDEVICIVEDRIVER_CLASS_NAME = %s\n,",CHARDEVICIVEDRIVER_CLASS_NAME);
	
	
	//注册cdev
	memset(&chardevicedriver_cdev,0,sizeof( struct cdev));
	cdev_init(&chardevicedriver_cdev,&chardevicedriver_fops);
	
	ret = cdev_add(&chardevicedriver_cdev,dev,CHARDEVICIVEDRIVER_COUNT);
	if(ret <0)
	{
		printk("chardevicedriver add dev failure\n");
		goto  failure_add_cdev;
	}
	printk("cdev_add hardevicedriver success\n");
	
	//create device for creating device file
	dev_device = device_create(dev_class,NULL,dev,NULL,"chardevicedriver%d",MINOR(dev));
	if(IS_ERR(dev_device))
	{
		printk("device create device failure\n");
		ret = PTR_ERR(dev_device);
		goto failure_create_device;
	}
	printk("device_create device success /dev/chardevicedriver%d\n",MINOR(dev));
	return ret;
	
	failure_create_device:
		cdev_del(&chardevicedriver_cdev);
	failure_add_cdev:
		class_destroy(dev_class);
	failure_create_class:
		unregister_chrdev_region(dev,CHARDEVICIVEDRIVER_COUNT);
	failure_register_chrdev:
		return ret;
}

static void __exit chardevicedriver_exit(void)
{
	printk("function = %s,line = %d\n",__FUNCTION__,__LINE__);
	
	//destroy device
	device_destroy(dev_class,MKDEV(chardevicedriver_major,chardevicedriver_minor));
	
	//delete cdev
	cdev_del(&chardevicedriver_cdev);
	
	//delete device class
	class_destroy(dev_class);
	//unregister device number
	unregister_chrdev_region(MKDEV(CHARDEVICIVEDRIVER_MAJOR,CHARDEVICIVEDRIVER_MINOR),CHARDEVICIVEDRIVER_COUNT);
}

module_init(chardevicedriver_init);
module_exit(chardevicedriver_exit);

MODULE_AUTHOR("tangtang");
MODULE_VERSION("0.0.1");

我们写一个简单的测试程序测试一下:

1_cdevapp.c

#include
#include
#include

int fd;
char ch;
char buf[10];

int main(int argc,char* argv[])
{
	fd = open("/dev/chardevicedriver0",O_RDWR);
	if(fd < 0)
	{		
		printf(" open char device driver failure\n");
		fd = open("/dev/chardevicedriver",O_RDWR);
		if(fd < 0)
		{
			printf(" open char device driver failure\n");
		}
	}

	if( fd > 0)
	{
		printf("open char device driver success\n");
	}
	return 0;
}

我们编译看看:

Linux 内核 设备号和struct file_operartion的使用_第1张图片

2,我们将add one cdev and create one device file封装一个函数来看看吧

#include
#include
#include
#include
#include
#include

MODULE_LICENSE("Dual BSD/GPL");

#define CHARDEVICIVEDRIVER_MAJOR 0
#define CHARDEVICIVEDRIVER_MINOR 0

#define CHARDEVICIVEDRIVER_COUNT 1
#define CHARDEVICIVEDRIVER_NAME "chardevicedriver"

#define CHARDEVICIVEDRIVER_CLASS_NAME "chardevicedriver_class"

static u32 chardevicedriver_major = CHARDEVICIVEDRIVER_MAJOR;
static u32 chardevicedriver_minor = CHARDEVICIVEDRIVER_MINOR;

struct chardevicedriver_cdev
{
	struct device* dev_device;//设备号
	struct cdev cdev;
};

static struct chardevicedriver_cdev* chardevicedriver_cdev = NULL;
static struct class* dev_class = NULL;//设备文件
static struct device* dev_device = NULL;//设备文件

static int chardevicedriver_open(struct inode* inode,struct file* file)
{
	printk("FILE = %s,FUNCTION = %s,LINE = %d\n",__FILE__,__FUNCTION__,__LINE__);
	return 0;
}

ssize_t chardevicedriver_read(struct file* file,char __user* buf,size_t count,loff_t* f_pos)
{
	printk("FILE = %s,FUNCTION = %s,LINE = %d\n",__FILE__,__FUNCTION__,__LINE__);
	return 0;
}

ssize_t chardevicedriver_write(struct file* file,const char __user* buf,size_t count,loff_t* f_pos)
{
	printk("FILE = %s,FUNCTION = %s,LINE = %d\n",__FILE__,__FUNCTION__,__LINE__);
	return 0;
}

long unlocked_chardevicedriver_ioctl(struct file* file,unsigned int cmd,unsigned long argc)
{
	printk("FILE = %s,FUNCTION = %s,LINE = %d\n",__FILE__,__FUNCTION__,__LINE__);
	return 0;
}

static int chardevicedriver_release(struct inode* inode,struct file* file)
{
	printk("FILE = %s,FUNCTION = %s,LINE = %d\n",__FILE__,__FUNCTION__,__LINE__);
	return 0;
}


static struct file_operations chardevicedriver_fops = {
		.owner = THIS_MODULE,
		.open = chardevicedriver_open,
		.write = chardevicedriver_write,
		.read = chardevicedriver_read,
		//.ioctl = chardevicedriver_ioctl,
	.unlocked_ioctl = unlocked_chardevicedriver_ioctl,
		.release = chardevicedriver_release,
};

//添加cdev并且创建一个设备文件
static int chardevicedriver_cdev_add(struct chardevicedriver_cdev* pcdev,int index)
{
	int ret = -1;
	dev_t dev = 0;
	printk("chardevicedriver+cdev_add enter success\n");
	
	dev = MKDEV(chardevicedriver_major,chardevicedriver_minor+index);
	cdev_init(&(pcdev->cdev),&chardevicedriver_fops);
	ret = cdev_add(&(pcdev->cdev),dev,CHARDEVICIVEDRIVER_COUNT);
	if(ret <0)
	{
		printk("cdev_add add dev to cdev failure\n");
		return ret;
	}
	printk("__FUNCTION = %s,dev add to c_dev success\n ",__FUNCTION__);
	
	//create device
	pcdev->dev_device = device_create(dev_class,NULL,dev,NULL,"chardevicedriver%d",MINOR(dev));
	if(IS_ERR(pcdev->dev_device))
	{
		printk("chardevicedriver:device_create failure\n");
		ret = PTR_ERR(pcdev->dev_device);
		return ret;
	}
	printk("chardevicedriver:class_device_craete success:/dev/chardevicedriver%d\n",MINOR(dev));
	
	return 0;
}

static int __init chardevicedriver_init(void)
{
	int ret = -1;
	dev_t dev = 0; //设备号
	printk("function = %s,line = %d\n",__FUNCTION__,__LINE__);
	if(chardevicedriver_major)
	{
		dev = MKDEV(CHARDEVICIVEDRIVER_MAJOR,CHARDEVICIVEDRIVER_MINOR);
	ret = register_chrdev_region(dev,CHARDEVICIVEDRIVER_COUNT,CHARDEVICIVEDRIVER_NAME);
		if(ret >0)
		{
			printk("register_chrdev_regin can't getr char device : major = %d,name = %s\n",\
			CHARDEVICIVEDRIVER_MAJOR,CHARDEVICIVEDRIVER_NAME);
			goto failure_register_chrdev;
		}
	}
	else
	{
		alloc_chrdev_region(&dev,chardevicedriver_minor,CHARDEVICIVEDRIVER_COUNT,CHARDEVICIVEDRIVER_NAME);
		chardevicedriver_major = MAJOR(dev);
		printk("chardevicedriver:chardevicedriver_major = %d,chardevicedriver_minor = %d\n",chardevicedriver_major,chardevicedriver_minor);
	}
	printk("register_chrdev_regin  : major = %d,name = %s\n",\
		CHARDEVICIVEDRIVER_MAJOR,CHARDEVICIVEDRIVER_NAME);
		
	//注册cdev
	chardevicedriver_cdev = kmalloc(sizeof(struct chardevicedriver_cdev)*CHARDEVICIVEDRIVER_COUNT,GFP_KERNEL);
	if(IS_ERR(chardevicedriver_cdev))
	{
		printk("chardevicedriver_cdevp:kmalloc space failure\n");
		ret = PTR_ERR(chardevicedriver_cdev);
		goto failure_alloc_cdev;
	}
	memset(chardevicedriver_cdev,0,sizeof(struct chardevicedriver_cdev)*(CHARDEVICIVEDRIVER_COUNT));
	
	//create device for create device file
	dev_class = class_create(THIS_MODULE,CHARDEVICIVEDRIVER_CLASS_NAME);
	if(IS_ERR(dev_class))
	{
		printk("__FUNCTION__:%s,device create failure\n",__FUNCTION__);
		ret = PTR_ERR(dev_device);
		goto failure_device_create;
	}
	printk("__FUNCTION__: device_create success:deice_name = %s\n",CHARDEVICIVEDRIVER_CLASS_NAME);
	
	ret = chardevicedriver_cdev_add(chardevicedriver_cdev,0);
	if(ret<0)
	{
		printk("chardevicedriver_cdev_add return failure\n");
		goto failure_add_cdev;
	}
	printk("chardevicedriver_cdev_add call success:\n");
	
	return ret;
	
	failure_add_cdev:
		class_destroy(dev_class);
	failure_device_create:
		kfree(chardevicedriver_cdev);
	failure_alloc_cdev:
		unregister_chrdev_region(dev,CHARDEVICIVEDRIVER_COUNT);
	failure_register_chrdev:
		return ret;
}

static void __exit chardevicedriver_exit(void)
{
	printk("function = %s,line = %d\n",__FUNCTION__,__LINE__);
	
	//delete cdev
	cdev_del(&(chardevicedriver_cdev->cdev));
	
	//destroy device class
	class_destroy(dev_class);
	kfree(chardevicedriver_cdev);
	chardevicedriver_cdev = NULL;
	unregister_chrdev_region(MKDEV(CHARDEVICIVEDRIVER_MAJOR,CHARDEVICIVEDRIVER_MINOR),CHARDEVICIVEDRIVER_COUNT);
}

module_init(chardevicedriver_init);
module_exit(chardevicedriver_exit);

MODULE_AUTHOR("tangtang");
MODULE_VERSION("0.0.1");

编译之后我们访问一下这个设备文件试试看 ,测试程序还是用上面哪一个:

Linux 内核 设备号和struct file_operartion的使用_第2张图片

 

 

 

 

 

 

 


 

 

 

你可能感兴趣的:(linux驱动入门)