每个字符设备的驱动都要包含对这个字符设备的初始化,而这个初始化其实是一个非常固定的步骤,接着我们就来看看这个初始化怎么写。
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基本相同,作用是销毁一个字符设备,用于驱动卸载。
这里介绍通过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);//销毁设备文件
举一个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);
}