字符设备驱动初始化和销毁部分

每个字符设备的驱动都要包含对这个字符设备的初始化,而这个初始化其实是一个非常固定的步骤,接着我们就来看看这个初始化怎么写。

1 申请注册一个设备(char 字符设备)

static inline int register_chrdev(unsigned int major, const char *name,
				  const struct file_operations *fops)

参数1-----major 表设备号(32位的值 由主+次设备号构成)高12位主设备号+低20位的次设备号构成

参数2-----name 表示设备名字

参数3-----file_operations表示文件操作集,是应用层要对设备进行的操作,常用的有:open,read,write

struct file_operations {
	struct module *owner;
	loff_t (*llseek) (struct file *, loff_t, int);
	ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
	ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
	ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
	ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
	int (*iterate) (struct file *, struct dir_context *);
	unsigned int (*poll) (struct file *, struct poll_table_struct *);
	long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
	long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
	int (*mmap) (struct file *, struct vm_area_struct *);
	int (*open) (struct inode *, struct file *);
	int (*flush) (struct file *, fl_owner_t id);
	int (*release) (struct inode *, struct file *);
	int (*fsync) (struct file *, loff_t, loff_t, int datasync);
	int (*aio_fsync) (struct kiocb *, int datasync);
	int (*fasync) (int, struct file *, int);
	int (*lock) (struct file *, int, struct file_lock *);
	ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
	unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
	int (*check_flags)(int);
	int (*flock) (struct file *, int, struct file_lock *);
	ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
	ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
	int (*setlease)(struct file *, long, struct file_lock **);
	long (*fallocate)(struct file *file, int mode, loff_t offset,
			  loff_t len);
	int (*show_fdinfo)(struct seq_file *m, struct file *f);
};

接着看一下和register_chrdev成对使用的函数:unregister_chrdev

static inline void unregister_chrdev(unsigned int major, const char *name)

参数和register_chrdev基本相同,作用是销毁一个字符设备,用于驱动卸载。

2 创建设备节点

这里介绍通过udev/mdev机制自动创建设备节点,我们需要做的是

1 创建一个类

struct class *class_create(owner, name)//创建一个类

参数1: THIS_MODULE

参数2: 名字(字符串),自定义

2 创建一个设备文件

struct device *device_create(struct class * class, struct device * 
	parent, dev_t devt, void * drvdata, const char * fmt,...)

参数1: class结构体,class_create调用之后到返回值

参数2:表示父亲,一般直接填NULL

参数3: 设备号类型 dev_t

参数4:私有数据,一般直接填NULL

参数5和6:表示可变参数,字符串,表示设备节点名字:(exp)led2、gpio ---->>/dev/led2 、gpio

 

3 在卸载驱动时需要注销这个类和设备文件,使用的结构函数是

void class_destroy(devcls);//销毁类
void device_destroy(struct class *class, dev_t devt);//销毁设备文件

 

3 例子

举一个MPU6050驱动中对其初始化的部分作为例子

struct dev_desc
{
	unsigned int my_major;
	struct class *class;//类
	struct device * dev;//自动创建设备节点/dev/xxx
	char *name;//节点
	struct i2c_client * client;
};

struct dev_desc mpu6050_dev_desc={
	.name = "mpu6050_drv",
};


static int chr_dev_init(struct dev_desc *S_led_dev,const struct file_operations *fops)
{
	int ret;
	
	if(S_led_dev->name == NULL)
		S_led_dev->name = "mpu_dev";
	S_led_dev->my_major = register_chrdev(0,S_led_dev->name,fops);
	
	if(S_led_dev->my_major <0)
	{
		printk(KERN_ERR "reg error!\n");
		goto err_0;		
	}
	else 
		printk("my_major =%d\n",S_led_dev->my_major);

	S_led_dev->class = class_create(THIS_MODULE,"mpu_class");//creat led_class
	if( IS_ERR(S_led_dev->class))
	{
		printk(KERN_ERR "fail create class\n");
		ret = PTR_ERR(S_led_dev->class);
		goto err_1;
	}
	
	
	S_led_dev->dev = device_create(S_led_dev->class, NULL,\
				MKDEV(S_led_dev->my_major,0), NULL, S_led_dev->name);//creat led_dev--->>

				
	if( IS_ERR(S_led_dev->dev))
	{
		printk(KERN_ERR "fail create device!\n");
		ret = PTR_ERR(S_led_dev->dev);
		goto err_2;		
	}
	
	return 0;
	

err_2:
		device_destroy(S_led_dev->class,MKDEV(S_led_dev->my_major,0));
err_1:
		class_destroy(S_led_dev->class);
err_0:
		unregister_chrdev(S_led_dev->my_major,S_led_dev->name);			
		return ret;
		
	return 0;

}

还有其对于的销毁部分

void chr_dev_exit(struct dev_desc *S_led_dev)
{

	printk("-------------%s------------\n",__FUNCTION__);
		
	device_destroy(S_led_dev->class,MKDEV(S_led_dev->my_major,0));

	class_destroy(S_led_dev->class);
	
	unregister_chrdev(S_led_dev->my_major, S_led_dev->name);	

}

 

你可能感兴趣的:(嵌入式驱动开发)